update
Some checks failed
CI / code-tests: ${{ matrix.os }} / ${{ matrix.platform }} (ubuntu-latest, x64) (push) Has been cancelled
CI / code-tests: ${{ matrix.os }} / ${{ matrix.platform }} (ubuntu-latest, x86) (push) Has been cancelled
CI / general_module_workflow_c (push) Has been cancelled

This commit is contained in:
Dennis Eichhorn 2024-06-01 23:53:22 +02:00
parent 02ee4480ad
commit e939a3f4a6
5 changed files with 312 additions and 84 deletions

101
Compression/LZP.h Normal file
View File

@ -0,0 +1,101 @@
/**
* Jingga
*
* @package Models
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://jingga.app
*/
#ifndef COMPRESSION_LZP_H
#define COMPRESSION_LZP_H
#include <stdio.h>
#include "../Stdlib/Types.h"
uint32 encode_lzp(const byte* in, uint32 length, byte* out)
{
byte buf[9];
byte table[1 << 16] = {0};
uint16 hash = 0;
int32 mask, i, j, c, in_pos = 0, out_pos = 0;
while(true) {
j = 1;
mask = 0;
for (i = 0; i < 8; ++i) {
if (in_pos == length) {
break;
}
c = in[in_pos++];
if (c == table[hash]) {
mask |= 1 << i;
} else {
table[hash] = c;
buf[j++] = c;
}
hash = (hash << 4) ^ c;
}
if (i > 0) {
buf[0] = mask;
for (i = 0; i < j; ++i) {
out[out_pos++] = buf[i];
}
}
if (in_pos == length) {
break;
}
}
return out_pos;
}
uint32 decode_lzp(const byte* in, uint32 length, byte* out)
{
byte buf[8];
byte table[1 << 16] = {0};
uint16 hash = 0;
int mask, i, j, c, in_pos = 0, out_pos = 0;
while (true) {
j = 0;
if (in_pos == length) {
break;
}
mask = in[in_pos++];
for (i = 0; i < 8; ++i) {
if ((mask & (1 << i)) != 0) {
c = table[hash];
} else {
if (in_pos == length) {
break;
}
c = in[in_pos++];
table[hash] = c;
}
buf[j++] = c;
hash = (hash << 4) ^ c;
}
if (j > 0) {
for (i = 0; i < j; ++i) {
out[out_pos++] = buf[i];
}
}
}
return out_pos;
}
#endif

View File

@ -25,8 +25,14 @@ namespace Sound {
uint32 sample_rate;
uint32 sample_size;
uint32 sample_index;
int16 volume;
uint32 buffer_size;
// Actual samples inside the buffer
// The buffer could be larger than the data to output
uint32 sample_buffer_size;
int16* buffer;
bool playing = false;
@ -61,6 +67,8 @@ namespace Sound {
if(!SUCCEEDED(setting->direct_sound->SetCooperativeLevel(w->hwnd, DSSCL_PRIORITY))) {
// @todo Log
return;
}
WAVEFORMATEX wf = {};
@ -81,13 +89,18 @@ namespace Sound {
if(!SUCCEEDED(setting->direct_sound->CreateSoundBuffer(&bufferDesc, &setting->primary_buffer, 0))) {
// @todo Log
return;
}
if (!SUCCEEDED(setting->primary_buffer->SetFormat(&wf))) {
// @todo Log
return;
}
setting->buffer_size = setting->sample_rate * setting->sample_size;
setting->buffer = (int16 *) calloc(setting->sample_rate, setting->sample_size);
// Create secondary buffer
DSBUFFERDESC bufferDesc2;
@ -100,15 +113,19 @@ namespace Sound {
if(!SUCCEEDED(setting->direct_sound->CreateSoundBuffer(&bufferDesc2, &setting->secondary_buffer, 0))) {
// @todo Log
return;
}
}
inline
void direct_sound_play(DirectSoundSetting* setting)
{
setting->secondary_buffer->Play(0, 0, DSBPLAY_LOOPING);
setting->playing = true;
}
inline
void direct_sound_free(DirectSoundSetting* setting)
{
if (setting->direct_sound) {
@ -124,31 +141,19 @@ namespace Sound {
}
}
bool direct_sound_should_update(DirectSoundSetting* setting)
{
return true;
}
int16 *direct_sound_return_buffer(DirectSoundSetting* setting)
{
}
void direct_sound_play_buffer(DirectSoundSetting* setting)
/**
* Calculates the samples in bytes to generate for the buffer
*/
inline
uint32 direct_sound_sample_buffer_size(const DirectSoundSetting* setting)
{
DWORD player_cursor;
DWORD write_cursor;
if (!SUCCEEDED(setting->secondary_buffer->GetCurrentPosition(&player_cursor, &write_cursor))) {
// @todo Log
return;
return 0;
}
void *region1;
DWORD region1_size;
void *region2;
DWORD region2_size;
DWORD bytes_to_lock = (setting->sample_index * setting->sample_size) % setting->buffer_size;
DWORD bytes_to_write = 0;
@ -161,6 +166,24 @@ namespace Sound {
bytes_to_write = player_cursor - bytes_to_lock;
}
return bytes_to_write;
}
inline
void direct_sound_play_buffer(DirectSoundSetting* setting, uint32 bytes_to_write)
{
if (bytes_to_write == 0) {
return;
}
void *region1;
DWORD region1_size;
void *region2;
DWORD region2_size;
DWORD bytes_to_lock = (setting->sample_index * setting->sample_size) % setting->buffer_size;
setting->secondary_buffer->Lock(
bytes_to_lock, bytes_to_write,
&region1, &region1_size,
@ -168,31 +191,28 @@ namespace Sound {
0
);
int16* sample_out = (int16 *) region1;
DWORD region1_sample_count = region1_size / setting->sample_size;
// @question Do we even need to use memcpy? Can't we use the buffer directly?
// Probably depends on what lock actually does to region1/region2
// Of course we would than need some mechanism to check when we can write into the buffer
// See XAudio2 for this, we would probably need a second buffer as well
memcpy(
(void *) region1,
(void *) setting->buffer,
region1_size
);
for (DWORD idx = 0; idx < region1_sample_count; ++idx) {
f32 t = ((f32) 1.0f / (f32) (48000 / 256)) * 2.0f * OMS_PI;
f32 sine_value = sinf(t);
int16 sample_value = (int16) (sine_value * setting->volume);
*sample_out++ = sample_value;
*sample_out++ = sample_value;
}
sample_out = (int16 *) region2;
DWORD region2_sample_count = region2_size / setting->sample_size;
for (DWORD idx = 0; idx < region2_sample_count; ++idx) {
f32 t = ((f32) 1.0f / (f32) (48000 / 256)) * 2.0f * OMS_PI;
f32 sine_value = sinf(t);
int16 sample_value = (int16) (sine_value * setting->volume);
*sample_out++ = sample_value;
*sample_out++ = sample_value;
if (region2_size > 0) {
memcpy(
(void *) region2,
(void *) (setting->buffer + region1_size),
region2_size
);
}
setting->secondary_buffer->Unlock(region1, region1_size, region2, region2_size);
setting->sample_index += bytes_to_write / setting->sample_size;
setting->sample_buffer_size = 0;
}
}

View File

@ -25,9 +25,16 @@ namespace Sound {
uint32 sample_rate;
uint32 sample_size;
uint32 sample_index;
int16 volume;
uint32 buffer_size;
// Actual samples inside the buffer
// The buffer could be larger than the data to output
uint32 sample_buffer_size;
int16* buffer;
bool playing = false;
byte type = SOUND_API_XAUDIO2;
@ -36,7 +43,7 @@ namespace Sound {
IXAudio2SourceVoice* source_voice;
IXAudio2MasteringVoice* mastering_voice;
XAUDIO2_BUFFER buffer[2];
XAUDIO2_BUFFER internal_buffer[2];
};
// BEGIN: Dynamically load XAudio2
@ -64,7 +71,13 @@ namespace Sound {
return;
}
if (!SUCCEEDED(setting->xaudio2->CreateMasteringVoice(&setting->mastering_voice))) {
if (!SUCCEEDED(setting->xaudio2->CreateMasteringVoice(
&setting->mastering_voice,
XAUDIO2_DEFAULT_CHANNELS,
setting->sample_rate,
0,
NULL
))) {
// @todo Log
return;
}
@ -72,10 +85,10 @@ namespace Sound {
WAVEFORMATEX wf = {};
wf.wFormatTag = WAVE_FORMAT_PCM;
wf.nChannels = 2;
wf.wBitsPerSample = 16;
wf.nBlockAlign = (wf.nChannels * wf.wBitsPerSample) / 8;
wf.wBitsPerSample = (uint16) ((setting->sample_size * 8) / wf.nChannels); // = sample_size per channel
wf.nBlockAlign = (wf.nChannels * wf.wBitsPerSample) / 8; // = sample_szie
wf.nSamplesPerSec = setting->sample_rate;
wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; // = buffer_size
wf.cbSize = 0;
if (!SUCCEEDED(setting->xaudio2->CreateSourceVoice(&setting->source_voice, &wf))) {
@ -83,32 +96,34 @@ namespace Sound {
return;
}
setting->buffer_size = setting->sample_rate * wf.nBlockAlign;
setting->buffer_size = setting->sample_rate * setting->sample_size;
setting->buffer = (int16 *) calloc(setting->sample_rate, setting->sample_size);
// @question Consider to move to the heap?
setting->buffer[0].Flags = 0;
setting->buffer[0].AudioBytes = setting->buffer_size;
setting->buffer[0].pAudioData = (BYTE *) malloc(setting->buffer_size * sizeof(BYTE));
setting->buffer[0].PlayBegin = 0;
setting->buffer[0].PlayLength = 0;
setting->buffer[0].LoopBegin = 0;
setting->buffer[0].LoopLength = 0;
setting->buffer[0].LoopCount = 0;
setting->buffer[0].pContext = NULL;
setting->internal_buffer[0].Flags = 0;
setting->internal_buffer[0].AudioBytes = setting->buffer_size;
setting->internal_buffer[0].pAudioData = (byte *) malloc(setting->buffer_size * sizeof(byte));
setting->internal_buffer[0].PlayBegin = 0;
setting->internal_buffer[0].PlayLength = 0;
setting->internal_buffer[0].LoopBegin = 0;
setting->internal_buffer[0].LoopLength = 0;
setting->internal_buffer[0].LoopCount = 0;
setting->internal_buffer[0].pContext = NULL;
setting->buffer[1].Flags = 0;
setting->buffer[1].AudioBytes = setting->buffer_size;
setting->buffer[1].pAudioData = (BYTE *) malloc(setting->buffer_size * sizeof(BYTE));
setting->buffer[1].PlayBegin = 0;
setting->buffer[1].PlayLength = 0;
setting->buffer[1].LoopBegin = 0;
setting->buffer[1].LoopLength = 0;
setting->buffer[1].LoopCount = 0;
setting->buffer[1].pContext = NULL;
setting->internal_buffer[1].Flags = 0;
setting->internal_buffer[1].AudioBytes = setting->buffer_size;
setting->internal_buffer[1].pAudioData = (byte *) malloc(setting->buffer_size * sizeof(byte));
setting->internal_buffer[1].PlayBegin = 0;
setting->internal_buffer[1].PlayLength = 0;
setting->internal_buffer[1].LoopBegin = 0;
setting->internal_buffer[1].LoopLength = 0;
setting->internal_buffer[1].LoopCount = 0;
setting->internal_buffer[1].pContext = NULL;
setting->sample_index = 0;
}
inline
void xaudio2_play(XAudio2Setting* setting) {
if (!setting->source_voice) {
// @todo Log
@ -120,14 +135,19 @@ namespace Sound {
setting->playing = true;
}
inline
void xaudio2_free(XAudio2Setting* setting)
{
if (setting->buffer[0].pAudioData) {
free((void *) setting->buffer[0].pAudioData);
if (setting->internal_buffer[0].pAudioData) {
free((void *) setting->internal_buffer[0].pAudioData);
}
if (setting->buffer[1].pAudioData) {
free((void *) setting->buffer[1].pAudioData);
if (setting->internal_buffer[1].pAudioData) {
free((void *) setting->internal_buffer[1].pAudioData);
}
if (setting->buffer) {
free((void *) setting->buffer);
}
if (setting->source_voice) {
@ -143,46 +163,55 @@ namespace Sound {
}
}
bool xaudio2_should_update(XAudio2Setting* setting)
/**
* Calculates the samples to generate for the buffer
*
* For XAudio2 we currently always fill the entire buffer size.
* For other audio APIs we maybe have to do something else
*/
inline
uint32 xaudio2_sample_buffer_size(XAudio2Setting* setting)
{
if (!setting->source_voice) {
// @todo Log
return false;
return 0;
}
XAUDIO2_VOICE_STATE state;
setting->source_voice->GetState(&state);
if (state.BuffersQueued > 1) {
return false;
return 0;
}
return true;
return setting->buffer_size;
}
int16* xaudio2_return_buffer(XAudio2Setting* setting)
{
return (int16 *) setting->buffer[setting->sample_index].pAudioData;
}
int16* xaudio2_fill_buffer(XAudio2Setting* setting, int16* buffer)
{
int16* sample_out = (int16 *) setting->buffer[setting->sample_index].pAudioData;
}
void xaudio2_play_buffer(XAudio2Setting* setting) {
inline
void xaudio2_play_buffer(XAudio2Setting* setting, uint32 bytes_to_write) {
if (!setting->source_voice) {
// @todo Log
return;
}
setting->sample_index = (setting->sample_index + 1) % 2;
if (bytes_to_write == 0) {
return;
}
if (!SUCCEEDED(setting->source_voice->SubmitSourceBuffer(&setting->buffer[setting->sample_index]))) {
memcpy(
(void *) setting->internal_buffer[setting->sample_index].pAudioData,
setting->buffer,
bytes_to_write
);
if (!SUCCEEDED(setting->source_voice->SubmitSourceBuffer(&setting->internal_buffer[setting->sample_index]))) {
// @todo Log
return;
}
setting->sample_index = (setting->sample_index + 1) % 2;
setting->sample_buffer_size = 0;
}
}

View File

@ -23,6 +23,7 @@ typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint16_t f16;
typedef float f32;
typedef double f64;
@ -32,4 +33,71 @@ typedef unsigned char byte;
#define local_persist static
#define global_persist static
#define HALF_FLOAT_SIGN_MASK 0x8000
#define HALF_FLOAT_EXP_MASK 0x7C00
#define HALF_FLOAT_FRAC_MASK 0x03FF
#define HALF_FLOAT_EXP_SHIFT 10
#define HALF_FLOAT_EXP_BIAS 15
#define FLOAT32_SIGN_MASK 0x80000000
#define FLOAT32_EXP_MASK 0x7F800000
#define FLOAT32_FRAC_MASK 0x007FFFFF
#define FLOAT32_EXP_SHIFT 23
#define FLOAT32_EXP_BIAS 127
uint16 float_to_f16(float f) {
uint32_t f_bits = *((uint32_t*)&f);
uint16_t f16_bits = 0;
// Extract sign, exponent, and fraction from float
uint16_t sign = (f_bits & FLOAT32_SIGN_MASK) >> 16;
int32_t exponent = ((f_bits & FLOAT32_EXP_MASK) >> FLOAT32_EXP_SHIFT) - FLOAT32_EXP_BIAS + HALF_FLOAT_EXP_BIAS;
uint32_t fraction = (f_bits & FLOAT32_FRAC_MASK) >> (FLOAT32_EXP_SHIFT - HALF_FLOAT_EXP_SHIFT);
if (exponent <= 0) {
if (exponent < -10) {
fraction = 0;
} else {
fraction = (fraction | 0x0400) >> (1 - exponent);
}
exponent = 0;
} else if (exponent >= 0x1F) {
exponent = 0x1F;
fraction = 0;
}
f16_bits = sign | (exponent << HALF_FLOAT_EXP_SHIFT) | (fraction & HALF_FLOAT_FRAC_MASK);
return f16_bits;
}
float f16_to_float(f16 f) {
uint32_t f_bits = 0;
uint32_t sign = (f & HALF_FLOAT_SIGN_MASK) << 16;
int32_t exponent = (f & HALF_FLOAT_EXP_MASK) >> HALF_FLOAT_EXP_SHIFT;
uint32_t fraction = (f & HALF_FLOAT_FRAC_MASK) << (FLOAT32_EXP_SHIFT - HALF_FLOAT_EXP_SHIFT);
if (exponent == 0) {
if (fraction != 0) {
exponent = 1;
while ((fraction & (1 << FLOAT32_EXP_SHIFT)) == 0) {
fraction <<= 1;
exponent--;
}
fraction &= ~FLOAT32_EXP_MASK;
}
} else if (exponent == 0x1F) {
exponent = 0xFF;
} else {
exponent += FLOAT32_EXP_BIAS - HALF_FLOAT_EXP_BIAS;
}
f_bits = sign | (exponent << FLOAT32_EXP_SHIFT) | fraction;
return *((float*)&f_bits);
}
#endif

View File

@ -27,6 +27,10 @@ namespace Test {
double dt = 0.0;
};
struct LogMessages {
char *messages;
};
void update_timing_stat(TimingStat *stat)
{
#ifdef _WIN32
@ -46,6 +50,12 @@ namespace Test {
}
}
#if DEBUG
#define UPDATE_TIMING_STAT(stat) Test::update_timing_stat(stat);
#else
#define UPDATE_TIMING_STAT(stat)
#endif
#define ASSERT_EQUALS(a, b, t1, t2) \
({ \
if ((a) == (b)) { \