Implement volume for C client

This commit is contained in:
UnknownShadow200 2018-08-22 22:27:06 +10:00
parent 912067ac99
commit 74a7c39a28
8 changed files with 98 additions and 90 deletions

View file

@ -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);

View file

@ -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; }

View file

@ -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;

View file

@ -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
*********************************************************************************************

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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] = {