mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-08 14:56:12 -04:00
Merge pull request #1166 from ClassiCube/AudioZip
Rewrite sounds so that they are loaded from a zip instead
This commit is contained in:
commit
d7b805a480
66
src/Audio.c
66
src/Audio.c
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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">
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
987
src/Resources.c
987
src/Resources.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
||||
|
13
src/Utils.c
13
src/Utils.c
@ -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',
|
||||
|
@ -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. */
|
||||
|
@ -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++)
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user