From 74a7c39a28063d913b28cdcea738d94f6b10a60b Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 22 Aug 2018 22:27:06 +1000 Subject: [PATCH] Implement volume for C client --- src/Audio.c | 116 ++++++++++++++++++++++++++++++++++--------------- src/Game.c | 1 - src/IModel.c | 29 ------------- src/IModel.h | 9 ---- src/Platform.c | 6 +-- src/Platform.h | 3 +- src/Program.c | 2 +- src/Vorbis.c | 22 +++++----- 8 files changed, 98 insertions(+), 90 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index 5ebd610e5..e8004071a 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -13,6 +13,33 @@ #include "Chat.h" StringsBuffer files; +static void Volume_Mix16(Int16* samples, Int32 count, Int32 volume) { + Int32 i; + + for (i = 0; i < (count & ~0x07); i += 8, samples += 8) { + samples[0] = (samples[0] * volume / 100); + samples[1] = (samples[1] * volume / 100); + samples[2] = (samples[2] * volume / 100); + samples[3] = (samples[3] * volume / 100); + + samples[4] = (samples[4] * volume / 100); + samples[5] = (samples[5] * volume / 100); + samples[6] = (samples[6] * volume / 100); + samples[7] = (samples[7] * volume / 100); + } + + for (; i < count; i++, samples++) { + samples[0] = (samples[0] * volume / 100); + } +} + +static void Volume_Mix8(UInt8* samples, Int32 count, Int32 volume) { + Int32 i; + for (i = 0; i < count; i++, samples++) { + samples[0] = (127 + (samples[0] - 127) * volume / 100); + } +} + /*########################################################################################################################* *------------------------------------------------------Soundboard---------------------------------------------------------* *#########################################################################################################################*/ @@ -153,15 +180,36 @@ struct Sound* Soundboard_PickRandom(struct Soundboard* board, UInt8 type) { /*########################################################################################################################* *--------------------------------------------------------Sounds-----------------------------------------------------------* *#########################################################################################################################*/ -struct Soundboard digBoard, stepBoard; +struct SoundOutput { AudioHandle Handle; void* Buffer; UInt32 BufferSize; }; #define AUDIO_MAX_HANDLES 6 -AudioHandle monoOutputs[AUDIO_MAX_HANDLES] = { -1, -1, -1, -1, -1, -1 }; -AudioHandle stereoOutputs[AUDIO_MAX_HANDLES] = { -1, -1, -1, -1, -1, -1 }; +#define HANDLE_INV -1 +#define SOUND_INV { HANDLE_INV, NULL, 0 } -static void Sounds_PlayRaw(AudioHandle output, struct Sound* snd, struct AudioFormat* fmt, Real32 volume) { - Audio_SetVolume(output, volume); - Audio_SetFormat(output, fmt); - Audio_PlayData(output, 0, snd->Data, snd->DataSize); +struct Soundboard digBoard, stepBoard; +struct SoundOutput monoOutputs[AUDIO_MAX_HANDLES] = { SOUND_INV, SOUND_INV, SOUND_INV, SOUND_INV, SOUND_INV, SOUND_INV }; +struct SoundOutput stereoOutputs[AUDIO_MAX_HANDLES] = { SOUND_INV, SOUND_INV, SOUND_INV, SOUND_INV, SOUND_INV, SOUND_INV }; + +static void Sounds_PlayRaw(struct SoundOutput* output, struct Sound* snd, struct AudioFormat* fmt, Int32 volume) { + Audio_SetFormat(output->Handle, fmt); + void* buffer = snd->Data; + /* copy to temp buffer to apply volume */ + + if (volume < 100) { + if (output->BufferSize < snd->DataSize) { + UInt32 expandBy = snd->DataSize - output->BufferSize; + Utils_Resize(&output->Buffer, &output->BufferSize, 1, 0, expandBy); + } + buffer = output->Buffer; + + Mem_Copy(buffer, snd->Data, snd->DataSize); + if (fmt->BitsPerSample == 8) { + Volume_Mix8(buffer, snd->DataSize, volume); + } else { + Volume_Mix16(buffer, snd->DataSize / 2, volume); + } + } + + Audio_PlayData(output->Handle, 0, buffer, snd->DataSize); /* TODO: handle errors here */ } @@ -171,32 +219,28 @@ static void Sounds_Play(UInt8 type, struct Soundboard* board) { if (snd == NULL) return; struct AudioFormat fmt = snd->Format; - Real32 volume = Game_SoundsVolume / 100.0f; + Int32 volume = Game_SoundsVolume; if (board == &digBoard) { if (type == SOUND_METAL) fmt.SampleRate = (fmt.SampleRate * 6) / 5; else fmt.SampleRate = (fmt.SampleRate * 4) / 5; } else { - volume *= 0.50f; + volume /= 2; if (type == SOUND_METAL) fmt.SampleRate = (fmt.SampleRate * 7) / 5; } - AudioHandle* outputs = NULL; - if (fmt.Channels == 1) outputs = monoOutputs; - if (fmt.Channels == 2) outputs = stereoOutputs; - if (outputs == NULL) return; /* TODO: > 2 channel sound?? */ + struct SoundOutput* outputs = fmt.Channels == 1 ? monoOutputs : stereoOutputs; Int32 i; /* Try to play on fresh device, or device with same data format */ for (i = 0; i < AUDIO_MAX_HANDLES; i++) { - AudioHandle output = outputs[i]; - if (output == -1) { - Audio_Init(&output, 1); - outputs[i] = output; + struct SoundOutput* output = &outputs[i]; + if (output->Handle == HANDLE_INV) { + Audio_Init(&output->Handle, 1); } - if (!Audio_IsFinished(output)) continue; + if (!Audio_IsFinished(output->Handle)) continue; - struct AudioFormat* l = Audio_GetFormat(output); + struct AudioFormat* l = Audio_GetFormat(output->Handle); if (l->Channels == 0 || AudioFormat_Eq(l, &fmt)) { Sounds_PlayRaw(output, snd, &fmt, volume); return; } @@ -204,8 +248,8 @@ static void Sounds_Play(UInt8 type, struct Soundboard* board) { /* Try again with all devices, even if need to recreate one (expensive) */ for (i = 0; i < AUDIO_MAX_HANDLES; i++) { - AudioHandle output = outputs[i]; - if (!Audio_IsFinished(output)) continue; + struct SoundOutput* output = &outputs[i]; + if (!Audio_IsFinished(output->Handle)) continue; Sounds_PlayRaw(output, snd, &fmt, volume); return; } @@ -219,23 +263,26 @@ static void Audio_PlayBlockSound(void* obj, Vector3I coords, BlockID oldBlock, B } } -static void Sounds_FreeOutputs(AudioHandle* outputs) { +static void Sounds_FreeOutputs(struct SoundOutput* outputs) { bool anyPlaying = true; Int32 i; while (anyPlaying) { anyPlaying = false; for (i = 0; i < AUDIO_MAX_HANDLES; i++) { - if (outputs[i] == -1) continue; - anyPlaying |= !Audio_IsFinished(outputs[i]); + if (outputs[i].Handle == HANDLE_INV) continue; + anyPlaying |= !Audio_IsFinished(outputs[i].Handle); } if (anyPlaying) Thread_Sleep(1); } for (i = 0; i < AUDIO_MAX_HANDLES; i++) { - if (outputs[i] == -1) continue; - Audio_Free(outputs[i]); - outputs[i] = -1; + if (outputs[i].Handle == HANDLE_INV) continue; + Audio_Free(outputs[i].Handle); + outputs[i].Handle = HANDLE_INV; + + Mem_Free(&outputs[i].Buffer); + outputs[i].BufferSize = 0; } } @@ -286,9 +333,10 @@ static ReturnCode Music_PlayOgg(struct Stream* source) { fmt.BitsPerSample = 16; Audio_SetFormat(music_out, &fmt); - /* largest possible vorbis frame decodes to blocksize1 samples */ + /* largest possible vorbis frame decodes to blocksize1 * channels samples */ /* so we may end up decoding slightly over a second of audio */ - Int32 chunkSize = (fmt.SampleRate + vorbis.BlockSizes[1]) * fmt.Channels; + Int32 chunkSize = fmt.Channels * (fmt.SampleRate + vorbis.BlockSizes[1]); + Int32 samplesPerSecond = fmt.Channels * fmt.SampleRate; Int16* data = Mem_Alloc(chunkSize * AUDIO_MAX_CHUNKS, sizeof(Int16), "Ogg - final PCM output"); for (;;) { @@ -304,15 +352,16 @@ static ReturnCode Music_PlayOgg(struct Stream* source) { Int16* base = data + (chunkSize * next); Int32 samples = 0; - while (samples < fmt.SampleRate) { + while (samples < samplesPerSecond) { res = Vorbis_DecodeFrame(&vorbis); if (res) break; - Int16* cur = &base[samples * fmt.Channels]; + Int16* cur = &base[samples]; samples += Vorbis_OutputFrame(&vorbis, cur); } - Audio_PlayData(music_out, next, base, samples * fmt.Channels * sizeof(Int16)); + if (Game_MusicVolume < 100) { Volume_Mix16(base, samples, Game_MusicVolume); } + Audio_PlayData(music_out, next, base, samples * sizeof(Int16)); /* need to specially handle last bit of audio */ if (res) break; } @@ -368,8 +417,7 @@ static void Music_RunLoop(void) { } static void Music_Init(void) { - if (music_thread) { Audio_SetVolume(music_out, Game_MusicVolume / 100.0f); return; } - + if (music_thread) return; music_pendingStop = false; Audio_Init(&music_out, AUDIO_MAX_CHUNKS); music_thread = Thread_Start(Music_RunLoop); diff --git a/src/Game.c b/src/Game.c index 86463ef84..497581413 100644 --- a/src/Game.c +++ b/src/Game.c @@ -748,7 +748,6 @@ void Game_Run(Int32 width, Int32 height, STRING_REF String* title, struct Displa /* TODO: fix all these stubs.... */ #include "Builder.h" void AdvLightingBuilder_SetActive(void) { NormalBuilder_SetActive(); } -void Audio_SetVolume(AudioHandle handle, Real32 volume) { } /* TODO: Initalise Shell, see https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx https://stackoverflow.com/questions/24590059/c-opening-a-url-in-default-browser-on-windows-without-admin-privileges */ ReturnCode Platform_StartShell(STRING_PURE String* args) { return 0; } diff --git a/src/IModel.c b/src/IModel.c index f96234ffe..77a05edc8 100644 --- a/src/IModel.c +++ b/src/IModel.c @@ -273,12 +273,6 @@ void BoxDesc_TexOrigin(struct BoxDesc* desc, Int32 x, Int32 y) { desc->TexX = x; desc->TexY = y; } -void BoxDesc_SetBounds(struct BoxDesc* desc, Real32 x1, Real32 y1, Real32 z1, Real32 x2, Real32 y2, Real32 z2) { - desc->X1 = x1 / 16.0f; desc->X2 = x2 / 16.0f; - desc->Y1 = y1 / 16.0f; desc->Y2 = y2 / 16.0f; - desc->Z1 = z1 / 16.0f; desc->Z2 = z2 / 16.0f; -} - void BoxDesc_Expand(struct BoxDesc* desc, Real32 amount) { amount /= 16.0f; desc->X1 -= amount; desc->X2 += amount; @@ -286,33 +280,10 @@ void BoxDesc_Expand(struct BoxDesc* desc, Real32 amount) { desc->Z1 -= amount; desc->Z2 += amount; } -void BoxDesc_Scale(struct BoxDesc* desc, Real32 scale) { - desc->X1 *= scale; desc->X2 *= scale; - desc->Y1 *= scale; desc->Y2 *= scale; - desc->Z1 *= scale; desc->Z2 *= scale; - desc->RotX *= scale; desc->RotY *= scale; desc->RotZ *= scale; -} - -void BoxDesc_RotOrigin(struct BoxDesc* desc, Int8 x, Int8 y, Int8 z) { - desc->RotX = (Real32)x / 16.0f; - desc->RotY = (Real32)y / 16.0f; - desc->RotZ = (Real32)z / 16.0f; -} - void BoxDesc_MirrorX(struct BoxDesc* desc) { Real32 temp = desc->X1; desc->X1 = desc->X2; desc->X2 = temp; } -void BoxDesc_Box(struct BoxDesc* desc, Int32 x1, Int32 y1, Int32 z1, Int32 x2, Int32 y2, Int32 z2) { - BoxDesc_TexOrigin(desc, 0, 0); - BoxDesc_RotOrigin(desc, 0, 0, 0); - BoxDesc_SetBounds(desc, (Real32)x1, (Real32)y1, (Real32)z1, (Real32)x2, (Real32)y2, (Real32)z2); - - desc->SizeZ = Math_AbsI(z2 - z1); - desc->SizeX = Math_AbsI(x2 - x1); - desc->SizeY = Math_AbsI(y2 - y1); -} - void BoxDesc_BuildBox(struct ModelPart* part, struct BoxDesc* desc) { Int32 sidesW = desc->SizeZ, bodyW = desc->SizeX, bodyH = desc->SizeY; diff --git a/src/IModel.h b/src/IModel.h index f9b316ab2..24dc1493e 100644 --- a/src/IModel.h +++ b/src/IModel.h @@ -91,20 +91,11 @@ struct BoxDesc { /* Sets the texture origin for this part within the texture atlas. */ void BoxDesc_TexOrigin(struct BoxDesc* desc, Int32 x, Int32 y); -/* Sets the the two corners of this box, in pixel coordinates. */ -void BoxDesc_SetBounds(struct BoxDesc* desc, Real32 x1, Real32 y1, Real32 z1, Real32 x2, Real32 y2, Real32 z2); /* Expands the corners of this box outwards by the given amount in pixel coordinates. */ void BoxDesc_Expand(struct BoxDesc* desc, Real32 amount); -/* Scales the corners of this box outwards by the given amounts. */ -void BoxDesc_Scale(struct BoxDesc* desc, Real32 scale); -/* Sets the coordinate that this box is rotated around, in pixel coordinates. */ -void BoxDesc_RotOrigin(struct BoxDesc* desc, Int8 x, Int8 y, Int8 z); /* Swaps the min and max X around, resulting in the part being drawn mirrored. */ void BoxDesc_MirrorX(struct BoxDesc* desc); -/* Constructs a description of the given box, from two corners. */ -void BoxDesc_Box(struct BoxDesc* desc, Int32 x1, Int32 y1, Int32 z1, Int32 x2, Int32 y2, Int32 z2); - /* Builds a box model assuming the follow texture layout: let SW = sides width, BW = body width, BH = body height ********************************************************************************************* diff --git a/src/Platform.c b/src/Platform.c index 949026038..585979932 100644 --- a/src/Platform.c +++ b/src/Platform.c @@ -894,7 +894,7 @@ ReturnCode Http_MakeRequest(struct AsyncRequest* request, void** handle) { } *handle = InternetOpenUrlA(hInternet, url.buffer, headers.buffer, headers.length, - INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, NULL); + INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, 0); return Win_Return(*handle); } @@ -935,7 +935,7 @@ ReturnCode Http_GetRequestData(struct AsyncRequest* request, void* handle, void* while (left > 0) { UInt32 toRead = left, avail = 0; /* only read as much data that is pending */ - if (InternetQueryDataAvailable(handle, &avail, 0, NULL)) { + if (InternetQueryDataAvailable(handle, &avail, 0, 0)) { toRead = min(toRead, avail); } @@ -1025,7 +1025,7 @@ void Audio_SetFormat(AudioHandle handle, struct AudioFormat* format) { fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; if (waveOutGetNumDevs() == 0u) ErrorHandler_Fail("No audio devices found"); - ReturnCode result = waveOutOpen(&ctx->Handle, WAVE_MAPPER, &fmt, NULL, NULL, CALLBACK_NULL); + ReturnCode result = waveOutOpen(&ctx->Handle, WAVE_MAPPER, &fmt, 0, 0, CALLBACK_NULL); ErrorHandler_CheckOrFail(result, "Audio - opening device"); ctx->Format = *format; } diff --git a/src/Platform.h b/src/Platform.h index 338b58447..13f2a8335 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -117,7 +117,7 @@ ReturnCode Http_FreeRequest(void* handle); ReturnCode Http_Free(void); #define AUDIO_MAX_CHUNKS 4 -struct AudioFormat { UInt8 Channels, BitsPerSample; Int32 SampleRate; }; +struct AudioFormat { UInt16 Channels, BitsPerSample; Int32 SampleRate; }; #define AudioFormat_Eq(a, b) ((a)->Channels == (b)->Channels && (a)->BitsPerSample == (b)->BitsPerSample && (a)->SampleRate == (b)->SampleRate) typedef Int32 AudioHandle; @@ -125,7 +125,6 @@ void Audio_Init(AudioHandle* handle, Int32 buffers); void Audio_Free(AudioHandle handle); struct AudioFormat* Audio_GetFormat(AudioHandle handle); void Audio_SetFormat(AudioHandle handle, struct AudioFormat* format); -void Audio_SetVolume(AudioHandle handle, Real32 volume); void Audio_PlayData(AudioHandle handle, Int32 idx, void* data, UInt32 dataSize); bool Audio_IsCompleted(AudioHandle handle, Int32 idx); bool Audio_IsFinished(AudioHandle handle); diff --git a/src/Program.c b/src/Program.c index e4f61e564..1fb4892bb 100644 --- a/src/Program.c +++ b/src/Program.c @@ -92,7 +92,7 @@ int main(void) { String title = String_FromConst(PROGRAM_APP_NAME); String rawArgs = Platform_GetCommandLineArgs(); /* NOTE: Make sure to comment this out before pushing a commit */ - rawArgs = String_FromReadonly("UnknownShadow200 fff 127.0.0.1 25565"); + //rawArgs = String_FromReadonly("UnknownShadow200 fff 127.0.0.1 25565"); String args[5]; Int32 argsCount = Array_Elems(args); String_UNSAFE_Split(&rawArgs, ' ', args, &argsCount); diff --git a/src/Vorbis.c b/src/Vorbis.c index 664cb0ade..822928460 100644 --- a/src/Vorbis.c +++ b/src/Vorbis.c @@ -172,7 +172,7 @@ static UInt32 Codebook_Pow(UInt32 base, UInt32 exp) { return result; } -static UInt32 lookup1_values(UInt32 entries, UInt32 dimensions) { +static UInt32 Codebook_Lookup1Values(UInt32 entries, UInt32 dimensions) { UInt32 i; /* the greatest integer value for which [value] to the power of [dimensions] is less than or equal to [entries] */ /* TODO: verify this */ @@ -286,14 +286,14 @@ static ReturnCode Codebook_DecodeSetup(struct VorbisState* ctx, struct Codebook* if (c->LookupType == 0) return 0; if (c->LookupType > 2) return VORBIS_ERR_CODEBOOK_LOOKUP; - c->MinValue = float32_unpack(ctx); - c->DeltaValue = float32_unpack(ctx); + c->MinValue = float32_unpack(ctx); + c->DeltaValue = float32_unpack(ctx); Int32 valueBits = Vorbis_ReadBits(ctx, 4); valueBits++; - c->SequenceP = Vorbis_ReadBits(ctx, 1); + c->SequenceP = Vorbis_ReadBits(ctx, 1); UInt32 lookupValues; if (c->LookupType == 1) { - lookupValues = lookup1_values(c->Entries, c->Dimensions); + lookupValues = Codebook_Lookup1Values(c->Entries, c->Dimensions); } else { lookupValues = c->Entries * c->Dimensions; } @@ -1311,11 +1311,11 @@ Int32 Vorbis_OutputFrame(struct VorbisState* ctx, Int16* data) { /* So for example, consider a short block overlapping with a long block a) we need to chop off 'prev' before its halfway point b) then need to chop off the 'cur' before the halfway point of 'prev' - |- ********|***** |- ********| - -| - * | *** | - * | - - | # | *** ===> | # | - - | * - | *** | * - | - ******-***|* - | *** |* - | + |- ********|***** |- ********| + -| - * | *** | - * | + - | # | *** ===> | # | + - | * - | *** | * - | + ******-***|* - | *** |* - | */ @@ -1350,7 +1350,7 @@ Int32 Vorbis_OutputFrame(struct VorbisState* ctx, Int16* data) { } ctx->PrevBlockSize = ctx->CurBlockSize; - return prevQrtr + curQrtr; + return (prevQrtr + curQrtr) * ctx->Channels; } static Real32 floor1_inverse_dB_table[256] = {