Merge pull request #1166 from ClassiCube/AudioZip

Rewrite sounds so that they are loaded from a zip instead
This commit is contained in:
UnknownShadow200 2024-04-03 20:08:54 +11:00 committed by GitHub
commit d7b805a480
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 630 additions and 469 deletions

View File

@ -12,11 +12,15 @@
#include "Stream.h" #include "Stream.h"
#include "Utils.h" #include "Utils.h"
#include "Options.h" #include "Options.h"
#include "Deflate.h"
#ifdef CC_BUILD_ANDROID #ifdef CC_BUILD_ANDROID
/* TODO: Refactor maybe to not rely on checking WinInfo.Handle != NULL */ /* TODO: Refactor maybe to not rely on checking WinInfo.Handle != NULL */
#include "Window.h" #include "Window.h"
#endif #endif
int Audio_SoundsVolume, Audio_MusicVolume; int Audio_SoundsVolume, Audio_MusicVolume;
const cc_string Sounds_ZipPathMC = String_FromConst("audio/default.zip");
const cc_string Sounds_ZipPathCC = String_FromConst("audio/classicube.zip");
static const cc_string audio_dir = String_FromConst("audio"); static const cc_string audio_dir = String_FromConst("audio");
struct Sound { struct Sound {
@ -91,7 +95,12 @@ static cc_result Sound_ReadWaveData(struct Stream* stream, struct Sound* snd) {
if ((res = Audio_AllocChunks(size, &snd->data, 1))) return res; if ((res = Audio_AllocChunks(size, &snd->data, 1))) return res;
snd->size = size; snd->size = size;
return Stream_Read(stream, (cc_uint8*)snd->data, size); res = Stream_Read(stream, (cc_uint8*)snd->data, size);
#ifdef CC_BUILD_BIGENDIAN
Utils_SwapEndian16((cc_int16*)snd->data, size / 2);
#endif
return res;
} }
/* Skip over unhandled data */ /* Skip over unhandled data */
@ -99,30 +108,18 @@ static cc_result Sound_ReadWaveData(struct Stream* stream, struct Sound* snd) {
} }
} }
static cc_result Sound_ReadWave(const cc_string* path, struct Sound* snd) { static struct SoundGroup* Soundboard_FindGroup(struct Soundboard* board, const cc_string* name) {
struct Stream stream;
cc_result res;
res = Stream_OpenFile(&stream, path);
if (res) return res;
res = Sound_ReadWaveData(&stream, snd);
/* No point logging error for closing readonly file */
(void)stream.Close(&stream);
return res;
}
static struct SoundGroup* Soundboard_Find(struct Soundboard* board, const cc_string* name) {
struct SoundGroup* groups = board->groups; struct SoundGroup* groups = board->groups;
int i; int i;
for (i = 0; i < SOUND_COUNT; i++) { for (i = 0; i < SOUND_COUNT; i++)
{
if (String_CaselessEqualsConst(name, Sound_Names[i])) return &groups[i]; if (String_CaselessEqualsConst(name, Sound_Names[i])) return &groups[i];
} }
return NULL; return NULL;
} }
static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName, const cc_string* file) { static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName, const cc_string* file, struct Stream* stream) {
struct SoundGroup* group; struct SoundGroup* group;
struct Sound* snd; struct Sound* snd;
cc_string name = *file; cc_string name = *file;
@ -139,7 +136,7 @@ static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName
name = String_UNSAFE_SubstringAt(&name, boardName->length); name = String_UNSAFE_SubstringAt(&name, boardName->length);
name = String_UNSAFE_Substring(&name, 0, name.length - 1); name = String_UNSAFE_Substring(&name, 0, name.length - 1);
group = Soundboard_Find(board, &name); group = Soundboard_FindGroup(board, &name);
if (!group) { if (!group) {
Chat_Add1("&cUnknown sound group '%s'", &name); return; Chat_Add1("&cUnknown sound group '%s'", &name); return;
} }
@ -148,7 +145,7 @@ static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName
} }
snd = &group->sounds[group->count]; snd = &group->sounds[group->count];
res = Sound_ReadWave(file, snd); res = Sound_ReadWaveData(stream, snd);
if (res) { if (res) {
Logger_SysWarn2(res, "decoding", file); Logger_SysWarn2(res, "decoding", file);
@ -219,12 +216,29 @@ static void Audio_PlayBlockSound(void* obj, IVec3 coords, BlockID old, BlockID n
} }
} }
static void Sounds_LoadFile(const cc_string* path, void* obj) { static cc_bool SelectZipEntry(const cc_string* path) { return true; }
static cc_result ProcessZipEntry(const cc_string* path, struct Stream* stream, struct ZipEntry* source) {
static const cc_string dig = String_FromConst("dig_"); static const cc_string dig = String_FromConst("dig_");
static const cc_string step = String_FromConst("step_"); static const cc_string step = String_FromConst("step_");
Soundboard_Load(&digBoard, &dig, path); Soundboard_Load(&digBoard, &dig, path, stream);
Soundboard_Load(&stepBoard, &step, path); Soundboard_Load(&stepBoard, &step, path, stream);
return 0;
}
static cc_result Sounds_ExtractZip(const cc_string* path) {
struct Stream stream;
cc_result res;
res = Stream_OpenFile(&stream, path);
if (res) { Logger_SysWarn2(res, "opening", path); return res; }
res = Zip_Extract(&stream, SelectZipEntry, ProcessZipEntry);
if (res) Logger_SysWarn2(res, "extracting", path);
/* No point logging error for closing readonly file */
(void)stream.Close(&stream);
return res;
} }
/* TODO this is a pretty terrible solution */ /* TODO this is a pretty terrible solution */
@ -269,6 +283,7 @@ static void InitWebSounds(void) {
static cc_bool sounds_loaded; static cc_bool sounds_loaded;
static void Sounds_Start(void) { static void Sounds_Start(void) {
cc_result res;
if (!AudioBackend_Init()) { if (!AudioBackend_Init()) {
AudioBackend_Free(); AudioBackend_Free();
Audio_SoundsVolume = 0; Audio_SoundsVolume = 0;
@ -280,7 +295,9 @@ static void Sounds_Start(void) {
#ifdef CC_BUILD_WEBAUDIO #ifdef CC_BUILD_WEBAUDIO
InitWebSounds(); InitWebSounds();
#else #else
Directory_Enum(&audio_dir, NULL, Sounds_LoadFile); res = Sounds_ExtractZip(&Sounds_ZipPathMC);
if (res == ReturnCode_FileNotFound)
Sounds_ExtractZip(&Sounds_ZipPathCC);
#endif #endif
} }
@ -335,7 +352,7 @@ static cc_result Music_Buffer(cc_int16* data, int maxSamples, struct VorbisState
static cc_result Music_PlayOgg(struct Stream* source) { static cc_result Music_PlayOgg(struct Stream* source) {
struct OggState ogg; struct OggState ogg;
struct VorbisState vorbis = { 0 }; struct VorbisState vorbis;
int channels, sampleRate, volume; int channels, sampleRate, volume;
int chunkSize, samplesPerSecond; int chunkSize, samplesPerSecond;
@ -344,6 +361,7 @@ static cc_result Music_PlayOgg(struct Stream* source) {
cc_result res; cc_result res;
Ogg_Init(&ogg, source); Ogg_Init(&ogg, source);
Vorbis_Init(&vorbis);
vorbis.source = &ogg; vorbis.source = &ogg;
if ((res = Vorbis_DecodeHeaders(&vorbis))) goto cleanup; if ((res = Vorbis_DecodeHeaders(&vorbis))) goto cleanup;

View File

@ -34,6 +34,8 @@ extern int Audio_SoundsVolume;
/* Volume music is played at, from 0-100. */ /* Volume music is played at, from 0-100. */
/* NOTE: Use Audio_SetMusic, don't change this directly. */ /* NOTE: Use Audio_SetMusic, don't change this directly. */
extern int Audio_MusicVolume; extern int Audio_MusicVolume;
extern const cc_string Sounds_ZipPathMC;
extern const cc_string Sounds_ZipPathCC;
void Audio_SetMusic(int volume); void Audio_SetMusic(int volume);
void Audio_SetSounds(int volume); void Audio_SetSounds(int volume);

View File

@ -620,9 +620,6 @@
<ClCompile Include="Platform_Dreamcast.c"> <ClCompile Include="Platform_Dreamcast.c">
<Filter>Source Files\Platform</Filter> <Filter>Source Files\Platform</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Window_Carbon.c">
<Filter>Source Files\Window</Filter>
</ClCompile>
<ClCompile Include="Window_Android.c"> <ClCompile Include="Window_Android.c">
<Filter>Source Files\Window</Filter> <Filter>Source Files\Window</Filter>
</ClCompile> </ClCompile>
@ -713,6 +710,9 @@
<ClCompile Include="Graphics_Xbox360.c"> <ClCompile Include="Graphics_Xbox360.c">
<Filter>Source Files\Graphics</Filter> <Filter>Source Files\Graphics</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="AudioBackend.c">
<Filter>Source Files\Audio</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="..\misc\windows\CCicon.rc"> <ResourceCompile Include="..\misc\windows\CCicon.rc">

View File

@ -1012,9 +1012,11 @@ static void CheckResourcesScreen_Next(void* w) {
} }
static void CheckResourcesScreen_AddWidgets(struct CheckResourcesScreen* s) { static void CheckResourcesScreen_AddWidgets(struct CheckResourcesScreen* s) {
const char* line1_msg = Resources_MissingRequired ? "Some required resources weren't found"
: "Some optional resources weren't found";
s->lblStatus.small = true; s->lblStatus.small = true;
LLabel_Add(s, &s->lblLine1, "Some required resources weren't found", cres_lblLine1); LLabel_Add(s, &s->lblLine1, line1_msg, cres_lblLine1);
LLabel_Add(s, &s->lblLine2, "Okay to download?", cres_lblLine2); LLabel_Add(s, &s->lblLine2, "Okay to download?", cres_lblLine2);
LLabel_Add(s, &s->lblStatus, "", cres_lblStatus); LLabel_Add(s, &s->lblStatus, "", cres_lblStatus);
@ -1030,7 +1032,7 @@ static void CheckResourcesScreen_Activated(struct LScreen* s_) {
float size; float size;
CheckResourcesScreen_AddWidgets(s); CheckResourcesScreen_AddWidgets(s);
size = Resources_Size / 1024.0f; size = Resources_MissingSize / 1024.0f;
String_InitArray(str, buffer); String_InitArray(str, buffer);
String_Format1(&str, "&eDownload size: %f2 megabytes", &size); String_Format1(&str, "&eDownload size: %f2 megabytes", &size);
LLabel_SetText(&s->lblStatus, &str); LLabel_SetText(&s->lblStatus, &str);
@ -1121,7 +1123,7 @@ static void FetchResourcesScreen_UpdateStatus(struct FetchResourcesScreen* s, in
String_InitArray(str, strBuffer); String_InitArray(str, strBuffer);
count = Fetcher_Downloaded + 1; count = Fetcher_Downloaded + 1;
String_Format3(&str, "&eFetching %c.. (%i/%i)", name, &count, &Resources_Count); String_Format3(&str, "&eFetching %c.. (%i/%i)", name, &count, &Resources_MissingCount);
if (String_Equals(&str, &s->lblStatus.text)) return; if (String_Equals(&str, &s->lblStatus.text)) return;
LLabel_SetText(&s->lblStatus, &str); LLabel_SetText(&s->lblStatus, &str);

View File

@ -260,7 +260,7 @@ void Launcher_Run(void) {
#ifdef CC_BUILD_RESOURCES #ifdef CC_BUILD_RESOURCES
Resources_CheckExistence(); Resources_CheckExistence();
if (Resources_Count) { if (Resources_MissingCount) {
CheckResourcesScreen_SetActive(); CheckResourcesScreen_SetActive();
} else { } else {
MainScreen_SetActive(); MainScreen_SetActive();

File diff suppressed because it is too large Load Diff

View File

@ -8,9 +8,11 @@ struct HttpRequest;
typedef void (*FetcherErrorCallback)(struct HttpRequest* req); typedef void (*FetcherErrorCallback)(struct HttpRequest* req);
/* Number of resources that need to be downloaded */ /* Number of resources that need to be downloaded */
extern int Resources_Count; extern int Resources_MissingCount;
/* Total size of resources that need to be downloaded */ /* Total size of resources that need to be downloaded */
extern int Resources_Size; extern int Resources_MissingSize;
/* Whether required resources need to be downloaded */
extern cc_bool Resources_MissingRequired;
/* Checks existence of all assets */ /* Checks existence of all assets */
void Resources_CheckExistence(void); void Resources_CheckExistence(void);

View File

@ -138,6 +138,19 @@ void Utils_Resize(void** buffer, int* capacity, cc_uint32 elemSize, int defCapac
} }
} }
void Utils_SwapEndian16(cc_int16* values, int numValues) {
cc_uint8* data = (cc_uint8*)values;
int i;
for (i = 0; i < numValues * 2; i += 2)
{
cc_uint8 tmp = data[i + 0];
data[i + 0] = data[i + 1];
data[i + 1] = tmp;
}
}
static const char base64_table[64] = { static const char base64_table[64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',

View File

@ -45,6 +45,7 @@ cc_uint32 Utils_CRC32(const cc_uint8* data, cc_uint32 length);
/* NOTE: This cannot be just indexed by byte value - see Utils_CRC32 implementation. */ /* NOTE: This cannot be just indexed by byte value - see Utils_CRC32 implementation. */
extern const cc_uint32 Utils_Crc32Table[256]; extern const cc_uint32 Utils_Crc32Table[256];
CC_NOINLINE void Utils_Resize(void** buffer, int* capacity, cc_uint32 elemSize, int defCapacity, int expandElems); CC_NOINLINE void Utils_Resize(void** buffer, int* capacity, cc_uint32 elemSize, int defCapacity, int expandElems);
void Utils_SwapEndian16(cc_int16* values, int numValues);
/* Converts blocks of 3 bytes into 4 ASCII characters. (pads if needed) */ /* Converts blocks of 3 bytes into 4 ASCII characters. (pads if needed) */
/* Returns the number of ASCII characters written. */ /* Returns the number of ASCII characters written. */

View File

@ -1229,6 +1229,10 @@ static void Vorbis_CalcWindow(struct VorbisWindow* window, int blockSize) {
} }
} }
void Vorbis_Init(struct VorbisState* ctx) {
Mem_Set(ctx, 0, sizeof(*ctx) - sizeof(ctx->imdct));
}
void Vorbis_Free(struct VorbisState* ctx) { void Vorbis_Free(struct VorbisState* ctx) {
int i; int i;
for (i = 0; i < ctx->numCodebooks; i++) for (i = 0; i < ctx->numCodebooks; i++)

View File

@ -56,7 +56,9 @@ struct VorbisState {
struct imdct_state imdct[2]; struct imdct_state imdct[2];
}; };
/* Frees all dynamic memory allocated to decode the given vorbis audio. */ /* Initialises the given context to defaults */
void Vorbis_Init(struct VorbisState* ctx);
/* Frees all memory dynamically allocated by the given context */
void Vorbis_Free(struct VorbisState* ctx); void Vorbis_Free(struct VorbisState* ctx);
/* Reads and decodes the initial vorbis headers and setup data. */ /* Reads and decodes the initial vorbis headers and setup data. */
cc_result Vorbis_DecodeHeaders(struct VorbisState* ctx); cc_result Vorbis_DecodeHeaders(struct VorbisState* ctx);