mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-01-25 18:42:08 -05:00
Implement volume for C client
This commit is contained in:
parent
912067ac99
commit
74a7c39a28
8 changed files with 98 additions and 90 deletions
116
src/Audio.c
116
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);
|
||||
|
|
|
@ -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; }
|
||||
|
|
29
src/IModel.c
29
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;
|
||||
|
|
|
@ -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
|
||||
*********************************************************************************************
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
22
src/Vorbis.c
22
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] = {
|
||||
|
|
Loading…
Add table
Reference in a new issue