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 "Utils.h"
#include "Options.h"
#include "Deflate.h"
#ifdef CC_BUILD_ANDROID
/* TODO: Refactor maybe to not rely on checking WinInfo.Handle != NULL */
#include "Window.h"
#endif
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");
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;
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 */
@ -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) {
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) {
static struct SoundGroup* Soundboard_FindGroup(struct Soundboard* board, const cc_string* name) {
struct SoundGroup* groups = board->groups;
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];
}
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 Sound* snd;
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_Substring(&name, 0, name.length - 1);
group = Soundboard_Find(board, &name);
group = Soundboard_FindGroup(board, &name);
if (!group) {
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];
res = Sound_ReadWave(file, snd);
res = Sound_ReadWaveData(stream, snd);
if (res) {
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 step = String_FromConst("step_");
Soundboard_Load(&digBoard, &dig, path);
Soundboard_Load(&stepBoard, &step, path);
Soundboard_Load(&digBoard, &dig, path, stream);
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 */
@ -269,6 +283,7 @@ static void InitWebSounds(void) {
static cc_bool sounds_loaded;
static void Sounds_Start(void) {
cc_result res;
if (!AudioBackend_Init()) {
AudioBackend_Free();
Audio_SoundsVolume = 0;
@ -280,7 +295,9 @@ static void Sounds_Start(void) {
#ifdef CC_BUILD_WEBAUDIO
InitWebSounds();
#else
Directory_Enum(&audio_dir, NULL, Sounds_LoadFile);
res = Sounds_ExtractZip(&Sounds_ZipPathMC);
if (res == ReturnCode_FileNotFound)
Sounds_ExtractZip(&Sounds_ZipPathCC);
#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) {
struct OggState ogg;
struct VorbisState vorbis = { 0 };
struct VorbisState vorbis;
int channels, sampleRate, volume;
int chunkSize, samplesPerSecond;
@ -344,6 +361,7 @@ static cc_result Music_PlayOgg(struct Stream* source) {
cc_result res;
Ogg_Init(&ogg, source);
Vorbis_Init(&vorbis);
vorbis.source = &ogg;
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. */
/* NOTE: Use Audio_SetMusic, don't change this directly. */
extern int Audio_MusicVolume;
extern const cc_string Sounds_ZipPathMC;
extern const cc_string Sounds_ZipPathCC;
void Audio_SetMusic(int volume);
void Audio_SetSounds(int volume);

View File

@ -620,9 +620,6 @@
<ClCompile Include="Platform_Dreamcast.c">
<Filter>Source Files\Platform</Filter>
</ClCompile>
<ClCompile Include="Window_Carbon.c">
<Filter>Source Files\Window</Filter>
</ClCompile>
<ClCompile Include="Window_Android.c">
<Filter>Source Files\Window</Filter>
</ClCompile>
@ -713,6 +710,9 @@
<ClCompile Include="Graphics_Xbox360.c">
<Filter>Source Files\Graphics</Filter>
</ClCompile>
<ClCompile Include="AudioBackend.c">
<Filter>Source Files\Audio</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<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) {
const char* line1_msg = Resources_MissingRequired ? "Some required resources weren't found"
: "Some optional resources weren't found";
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->lblStatus, "", cres_lblStatus);
@ -1030,7 +1032,7 @@ static void CheckResourcesScreen_Activated(struct LScreen* s_) {
float size;
CheckResourcesScreen_AddWidgets(s);
size = Resources_Size / 1024.0f;
size = Resources_MissingSize / 1024.0f;
String_InitArray(str, buffer);
String_Format1(&str, "&eDownload size: %f2 megabytes", &size);
LLabel_SetText(&s->lblStatus, &str);
@ -1121,7 +1123,7 @@ static void FetchResourcesScreen_UpdateStatus(struct FetchResourcesScreen* s, in
String_InitArray(str, strBuffer);
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;
LLabel_SetText(&s->lblStatus, &str);

View File

@ -260,7 +260,7 @@ void Launcher_Run(void) {
#ifdef CC_BUILD_RESOURCES
Resources_CheckExistence();
if (Resources_Count) {
if (Resources_MissingCount) {
CheckResourcesScreen_SetActive();
} else {
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);
/* 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 */
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 */
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] = {
'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',

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. */
extern const cc_uint32 Utils_Crc32Table[256];
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) */
/* 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) {
int i;
for (i = 0; i < ctx->numCodebooks; i++)

View File

@ -56,7 +56,9 @@ struct VorbisState {
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);
/* Reads and decodes the initial vorbis headers and setup data. */
cc_result Vorbis_DecodeHeaders(struct VorbisState* ctx);