v0.01.003 - Mouse pointers, Audio improvement & features, bug fixes

This commit is contained in:
Charlie Malmqvist 2024-08-03 16:40:41 +02:00
parent b631b96e62
commit d89ef01fa6
7 changed files with 150 additions and 61 deletions

23
TODO
View file

@ -1,6 +1,6 @@
- Gamepad
- Audio - Audio
- Avoid playing identical audio at the same time
- Allow audio programming - Allow audio programming
- Inject mixer proc per player - Inject mixer proc per player
- Inject a mixer proc before and after filling output buffer - Inject a mixer proc before and after filling output buffer
@ -9,14 +9,13 @@
- Handle audio sources which had their format defaulted to update when default device changes - Handle audio sources which had their format defaulted to update when default device changes
For streamed audio sources this should be easy enough, because the conversion happens from raw format to source format as we stream it. For streamed audio sources this should be easy enough, because the conversion happens from raw format to source format as we stream it.
For loaded sources though, we would need to convert the source->pcm_frames. For loaded sources though, we would need to convert the source->pcm_frames.
Probably just dirty flag
- Optimize - Optimize
- Spam simd - Spam simd
- Concurrent jobs for players?
- Pool of intermediate buffers (2^) - Pool of intermediate buffers (2^)
- Bugs: - Bugs / Issues:
- Small fadeout on pause is slightly noisy - Small fadeout on start/pause is sometimes noisy
- Setting time stamp/progression causes noise (need fade transition like on pause/play) - If audio starts/end abrubtly we will get noise. Maybe detect that on load and apply small fade in/out?
- End of clip also causes noise if audio clip does not end smoothly
- Setting audio source to a format which differs from audio output format in both channels and bit_width at the same time will produce pure loud noise. - Setting audio source to a format which differs from audio output format in both channels and bit_width at the same time will produce pure loud noise.
- 24-Bit audio conversion doesn't really work - 24-Bit audio conversion doesn't really work
@ -38,12 +37,14 @@
- OS - OS
- Window::bool is_minimized - Window::bool is_minimized
- don't set window.width & window.height to 0 - don't set window.width & window.height to 0
- Handle monitor change
- Sockets recv, send - Sockets recv, send
- Mouse pointer - Mouse pointer
- Hide mouse pointer - Hide mouse pointer
- Better hash table
- Memory - Memory
- In heap allocator, mark pages that fit entirely into free nodes as NOACCESS
- Arenas - Arenas
- Examples/Guides: - Examples/Guides:
@ -51,13 +52,19 @@
- Z sorting - Z sorting
- Scissor boxing - Scissor boxing
- Concurrency - Concurrency
- strings
- Rework profiler - Rework profiler
- Store records and convert to google trace format on exit - Store records and convert to google trace format on exit
- Measure both time and cycles, output a google_trace_cycles.json & google_trace_time.json - Measure both time and cycles, output a google_trace_cycles.json & google_trace_time.json
- Concurrency
- Event objects for binary semaphore
- Needs testing: - Needs testing:
- Audio format channel conversions - Audio format channel conversions
- sample rate downsampling - sample rate downsampling
- non stereo or mono audio - non stereo or mono audio
- Audio spacialization on anything that's not stereo - Audio spacialization on anything that's not stereo
- Compiling with msvc
- Compiling with gcc

View file

@ -1,8 +1,12 @@
## v0.01.003 - Stuff ## v0.01.003 - Mouse pointers, Audio improvement & features, bug fixes
- Os layer - Os layer
- Implemented setting of mouse pointers, either to system standard pointers or a custom image - Implemented setting of mouse pointers, either to system standard pointers or a custom image
- Ignore SETCURSOR events unless window resize os_set_mouse_pointer_standard(kind)
os_set_mouse_pointer_custom(pointer)
os_make_custom_mouse_pointer(image, width, height, hotspot_x, hotspot_y)
os_make_custom_mouse_pointer_from_file(path, hotspot_x, hotspot_y, allocator)
- Ignore SETCURSOR events unless for window resize pointer
- Store SYSTEM_INFO in init - Store SYSTEM_INFO in init
- os_get_number_of_logical_processors() - os_get_number_of_logical_processors()
@ -15,14 +19,35 @@
- os_lock_program_memory_pages - os_lock_program_memory_pages
- Heap locks pages when completely free - Heap locks pages when completely free
- Audio
- Implemented playback speed configuration
- Implemented a way to recognize audio sources which start playing at the exact same time so we can avoid phase cancellation
- Refactor playback configuration members in Audio_Player to be in a struct Audio_Playback_Configuration
Example: player.volume -> player.config.volume
- bool disable_spacialization -> bool enable_spacialization (inverted)
- Deprecated:
play_one_audio_clip_source_at_position()
play_one_audio_clip_at_position()
- Added:
play_one_audio_clip_source_with_config()
play_one_audio_clip_with_config()
- Removed 'bool retain_progression_factor' parameter in audio_player_set_source()
- Fixed a bug where players didn't loop when set to do so
- Fixed a bug where wav sources would return 4 garbage samples at the start of playback, causing a glitch in the sound
- Fixed a crash when default audio device could not be initialized
- Fixed a bunch of bugs & woopsies
- Updated audio_test.c
- Misc - Misc
- Deprecate Rangef stuff - Deprecated Rangef stuff
- peek_random() - added peek_random()
- Update #Contributions - Updated #Contributions
- Clean up memory barriers in concurrency.c and use volatile instead - Cleaned up memory barriers in concurrency.c and use volatile instead
- Output d3d11 debug messages before crash on hr fail - Made hr fails output d3d11 debug messages before crash
- Configurable temporary storage size for new threads - Made temporary storage size runtime-configurable for new threads
- Cleanup temporary storage after thread destroy - Cleanup temporary storage after thread destroy
- Added Header checking in growing array
- Unfucked linmath alignment
## v0.01.002 - Flexible build options, Hotloading, growing array ## v0.01.002 - Flexible build options, Hotloading, growing array

View file

@ -249,7 +249,7 @@ typedef struct Cpu_Capabilities {
#define COMPILER_CAN_DO_AVX2 0 #define COMPILER_CAN_DO_AVX2 0
#define COMPILER_CAN_DO_AVX512 0 #define COMPILER_CAN_DO_AVX512 0
#define deprecated(msg) #define DEPRECATED(proc, msg)
#define MEMORY_BARRIER #define MEMORY_BARRIER

View file

@ -31,7 +31,7 @@ int entry(int argc, char **argv) {
bool bruh_ok = audio_open_source_load(&bruh, STR("oogabooga/examples/bruh.wav"), heap); bool bruh_ok = audio_open_source_load(&bruh, STR("oogabooga/examples/bruh.wav"), heap);
assert(bruh_ok, "Could not load bruh.wav"); assert(bruh_ok, "Could not load bruh.wav");
bool song_ok = audio_open_source_stream_format(&song, STR("oogabooga/examples/song.ogg"), heap); bool song_ok = audio_open_source_stream(&song, STR("oogabooga/examples/song.ogg"), heap);
assert(song_ok, "Could not load song.ogg"); assert(song_ok, "Could not load song.ogg");
// By default, audio sources will be converted to the same format as the output buffer. // By default, audio sources will be converted to the same format as the output buffer.

View file

@ -102,7 +102,7 @@ int entry(int argc, char **argv) {
v2(input_frame.mouse_x+256, input_frame.mouse_y+256) v2(input_frame.mouse_x+256, input_frame.mouse_y+256)
); );
} }
seed_for_random = 69; seed_for_random = 69;
for (u64 i = 0; i < 30000; i++) { for (u64 i = 0; i < 30000; i++) {
float32 aspect = (float32)window.width/(float32)window.height; float32 aspect = (float32)window.width/(float32)window.height;
@ -113,7 +113,7 @@ int entry(int argc, char **argv) {
float x = get_random_float32() * (max_x-min_x) + min_x; float x = get_random_float32() * (max_x-min_x) + min_x;
float y = get_random_float32() * (max_y-min_y) + min_y; float y = get_random_float32() * (max_y-min_y) + min_y;
push_z_layer((s32)(y*100)); push_z_layer((s32)(y*100));
draw_image(bush_image, v2(x, y), v2(0.1, 0.1), COLOR_WHITE); draw_image(bush_image, v2(x, y), v2(0.1, 0.1), COLOR_WHITE);
pop_z_layer(); pop_z_layer();

View file

@ -1,46 +1,85 @@
/* /*
Thing *things; Full API:
growing_array_init(&things, sizeof(Thing));
void growing_array_init_reserve(void **array, u64 block_size_in_bytes, u64 count_to_reserve, Allocator allocator);
growing_array_deinit(&things); void growing_array_init(void **array, u64 block_size_in_bytes, Allocator allocator);
void growing_array_deinit(void **array);
Thing new_thing;
growing_array_add(&things, &new_thing); // 'thing' is copied void *growing_array_add_empty(void **array);
void growing_array_add(void **array, void *item);
Thing *nth_thing = &things[n];
void growing_array_reserve(void **array, u64 count_to_reserve);
growing_array_reserve_count(&things, 690); void growing_array_resize(void **array, u64 new_count);
growing_array_resize_count(&things, 69); void growing_array_pop(void **array);
void growing_array_clear(void **array);
// "Slow", but stuff in the array keeps the same order
growing_array_ordered_remove_by_index(&things, i); // Returns -1 if not found
s32 growing_array_find_index_from_left_by_pointer(void **array, void *p);
// Fast, but will not keep stuff ordered s32 growing_array_find_index_from_left_by_value(void **array, void *p);
growing_array_unordered_remove_by_index(&things, i);
void growing_array_ordered_remove_by_index(void **array, u32 index);
growing_array_ordered_remove_by_pointer(&things, nth_thing); void growing_array_unordered_remove_by_index(void **array, u32 index);
growing_array_unordered_remove_by_pointer(&things, nth_thing); bool growing_array_ordered_remove_by_pointer(void **array, void *p);
bool growing_array_unordered_remove_by_pointer(void **array, void *p);
Thing thing_prototype; bool growing_array_ordered_remove_one_by_value(void **array, void *p);
growing_array_ordered_remove_one_by_value(&things, thing_prototype); bool growing_array_unordered_remove_one_by_value(void **array, void *p);
growing_array_unordered_remove_one_by_value(&things, thing_prototype);
growing_array_ordered_remove_all_by_value(&things, thing_prototype); u32 growing_array_get_valid_count(void *array);
growing_array_unordered_remove_all_by_value(&things, thing_prototype); u32 growing_array_get_allocated_count(void *array);
growing_array_get_valid_count(&things); Usage:
growing_array_get_allocated_count(&things);
Thing *things;
growing_array_init(&things, sizeof(Thing));
growing_array_deinit(&things);
Thing new_thing;
growing_array_add(&things, &new_thing); // 'thing' is copied
Thing *nth_thing = &things[n];
growing_array_reserve_count(&things, 690);
growing_array_resize_count(&things, 69);
// "Slow", but stuff in the array keeps the same order
growing_array_ordered_remove_by_index(&things, i);
// Fast, but will not keep stuff ordered
growing_array_unordered_remove_by_index(&things, i);
growing_array_ordered_remove_by_pointer(&things, nth_thing);
growing_array_unordered_remove_by_pointer(&things, nth_thing);
Thing thing_prototype;
growing_array_ordered_remove_one_by_value(&things, thing_prototype);
growing_array_unordered_remove_one_by_value(&things, thing_prototype);
growing_array_ordered_remove_all_by_value(&things, thing_prototype);
growing_array_unordered_remove_all_by_value(&things, thing_prototype);
growing_array_get_valid_count(&things);
growing_array_get_allocated_count(&things);
*/ */
#define GROWING_ARRAY_SIGNATURE 2224364215
typedef struct Growing_Array_Header { typedef struct Growing_Array_Header {
u32 signature;
u32 valid_count; u32 valid_count;
u32 allocated_count; u32 allocated_count;
u32 block_size_in_bytes; u32 block_size_in_bytes;
Allocator allocator; Allocator allocator;
} Growing_Array_Header; } Growing_Array_Header;
bool
check_growing_array_signature(void **array) {
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
if (header->signature != GROWING_ARRAY_SIGNATURE) return false;
return true;
}
void void
growing_array_init_reserve(void **array, u64 block_size_in_bytes, u64 count_to_reserve, Allocator allocator) { growing_array_init_reserve(void **array, u64 block_size_in_bytes, u64 count_to_reserve, Allocator allocator) {
@ -54,6 +93,7 @@ growing_array_init_reserve(void **array, u64 block_size_in_bytes, u64 count_to_r
header->block_size_in_bytes = block_size_in_bytes; header->block_size_in_bytes = block_size_in_bytes;
header->valid_count = 0; header->valid_count = 0;
header->allocated_count = count_to_reserve; header->allocated_count = count_to_reserve;
header->signature = GROWING_ARRAY_SIGNATURE;
*array = header+1; *array = header+1;
} }
@ -63,12 +103,14 @@ growing_array_init(void **array, u64 block_size_in_bytes, Allocator allocator) {
} }
void void
growing_array_deinit(void **array) { growing_array_deinit(void **array) {
assert(check_growing_array_signature(array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
dealloc(header->allocator, header); dealloc(header->allocator, header);
} }
void void
growing_array_reserve(void **array, u64 count_to_reserve) { growing_array_reserve(void **array, u64 count_to_reserve) {
assert(check_growing_array_signature(array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
if (header->allocated_count >= count_to_reserve) return; if (header->allocated_count >= count_to_reserve) return;
@ -90,6 +132,7 @@ growing_array_reserve(void **array, u64 count_to_reserve) {
void* void*
growing_array_add_empty(void **array) { growing_array_add_empty(void **array) {
assert(check_growing_array_signature(array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
growing_array_reserve(array, header->valid_count+1); growing_array_reserve(array, header->valid_count+1);
@ -119,18 +162,21 @@ void growing_array_resize(void **array, u64 new_count) {
} }
void growing_array_pop(void **array) { void growing_array_pop(void **array) {
assert(check_growing_array_signature(array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
assert(header->valid_count > 0, "No items to pop in growing array"); assert(header->valid_count > 0, "No items to pop in growing array");
header->valid_count -= 1; header->valid_count -= 1;
} }
void growing_array_clear(void **array) { void growing_array_clear(void **array) {
assert(check_growing_array_signature(array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
header->valid_count = 0; header->valid_count = 0;
} }
void void
growing_array_ordered_remove_by_index(void **array, u32 index) { growing_array_ordered_remove_by_index(void **array, u32 index) {
assert(check_growing_array_signature(array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
assert(index < header->valid_count, "Growing array index out of range"); assert(index < header->valid_count, "Growing array index out of range");
@ -150,6 +196,7 @@ growing_array_ordered_remove_by_index(void **array, u32 index) {
} }
void void
growing_array_unordered_remove_by_index(void **array, u32 index) { growing_array_unordered_remove_by_index(void **array, u32 index) {
assert(check_growing_array_signature(array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
assert(index < header->valid_count, "Growing array index out of range"); assert(index < header->valid_count, "Growing array index out of range");
@ -171,6 +218,7 @@ growing_array_unordered_remove_by_index(void **array, u32 index) {
s32 s32
growing_array_find_index_from_left_by_pointer(void **array, void *p) { growing_array_find_index_from_left_by_pointer(void **array, void *p) {
assert(check_growing_array_signature(array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
for (u32 i = 0; i < header->valid_count; i++) { for (u32 i = 0; i < header->valid_count; i++) {
@ -184,6 +232,7 @@ growing_array_find_index_from_left_by_pointer(void **array, void *p) {
} }
s32 s32
growing_array_find_index_from_left_by_value(void **array, void *p) { growing_array_find_index_from_left_by_value(void **array, void *p) {
assert(check_growing_array_signature(array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
for (u32 i = 0; i < header->valid_count; i++) { for (u32 i = 0; i < header->valid_count; i++) {
@ -251,11 +300,13 @@ growing_array_unordered_remove_one_by_value(void **array, void *p) {
u32 u32
growing_array_get_valid_count(void *array) { growing_array_get_valid_count(void *array) {
assert(check_growing_array_signature(&array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)array) - 1;
return header->valid_count; return header->valid_count;
} }
u32 u32
growing_array_get_allocated_count(void *array) { growing_array_get_allocated_count(void *array) {
assert(check_growing_array_signature(&array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)array) - 1; Growing_Array_Header *header = ((Growing_Array_Header*)array) - 1;
return header->allocated_count; return header->allocated_count;
} }

View file

@ -396,6 +396,11 @@ void os_init(u64 program_memory_capacity) {
#ifndef OOGABOOGA_HEADLESS #ifndef OOGABOOGA_HEADLESS
win32_init_window(); win32_init_window();
// Set a dummy output format before audio init in case it fails.
audio_output_format.sample_rate = 48000;
audio_output_format.channels = 2;
audio_output_format.bit_width = AUDIO_BITS_32;
local_persist Thread audio_thread, audio_poll_default_device_thread; local_persist Thread audio_thread, audio_poll_default_device_thread;
os_thread_init(&audio_thread, win32_audio_thread); os_thread_init(&audio_thread, win32_audio_thread);
@ -1416,8 +1421,6 @@ const GUID CLSID_MMDeviceEnumerator = {0xbcde0395, 0xe52f, 0x467c, {0x8e,0x3d, 0
const GUID IID_IMMDeviceEnumerator = {0xa95664d2, 0x9614, 0x4f35, {0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6}}; const GUID IID_IMMDeviceEnumerator = {0xa95664d2, 0x9614, 0x4f35, {0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6}};
const GUID IID_IAudioClient = {0x1cb9ad4c, 0xdbfa, 0x4c32, {0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2}}; const GUID IID_IAudioClient = {0x1cb9ad4c, 0xdbfa, 0x4c32, {0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2}};
const GUID IID_IAudioRenderClient = {0xf294acfc, 0x3146, 0x4483, {0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2}}; const GUID IID_IAudioRenderClient = {0xf294acfc, 0x3146, 0x4483, {0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2}};
DEFINE_GUID(IID_ISimpleAudioVolume,
0x87CE5498, 0x68D6, 0x44E5, 0x92, 0x15, 0x6D, 0xA4, 0x7E, 0xF8, 0x83, 0xD8);
IAudioClient* win32_audio_client; IAudioClient* win32_audio_client;
IAudioRenderClient* win32_render_client; IAudioRenderClient* win32_render_client;
@ -1425,12 +1428,13 @@ bool win32_audio_deactivated = false;
Audio_Format audio_output_format; // For use when loading audio sources Audio_Format audio_output_format; // For use when loading audio sources
IMMDevice* win32_audio_device = 0; IMMDevice* win32_audio_device = 0;
IMMDeviceEnumerator* win32_device_enumerator = 0; IMMDeviceEnumerator* win32_device_enumerator = 0;
ISimpleAudioVolume* win32_audio_volume = 0;
Mutex audio_init_mutex; Mutex audio_init_mutex;
void void
win32_audio_init() { win32_audio_init() {
local_persist bool did_report_error_last_call = false;
win32_audio_client = 0; win32_audio_client = 0;
win32_render_client = 0; win32_render_client = 0;
win32_audio_deactivated = 0; win32_audio_deactivated = 0;
@ -1502,7 +1506,8 @@ win32_audio_init() {
); );
if (hr != S_OK) { if (hr != S_OK) {
win32_audio_deactivated = true; win32_audio_deactivated = true;
log_error("Default audio output device is not supported."); if (!did_report_error_last_call) log_error("Default audio output device is not supported.");
did_report_error_last_call = true;
return; return;
} }
output_format = (WAVEFORMATEX*)format_s16; output_format = (WAVEFORMATEX*)format_s16;
@ -1518,6 +1523,12 @@ win32_audio_init() {
BUFFER_DURATION_MS*10000ll, 0, BUFFER_DURATION_MS*10000ll, 0,
output_format, 0 output_format, 0
); );
if (hr == 0x8889000A) {
if (!did_report_error_last_call) log_error("IAudioClient_Initialize failed for default device\nSample rate: %d\nBit-width: %d\n Channels: %d", device_base_format->nSamplesPerSec, device_base_format->wBitsPerSample, device_base_format->nChannels);
win32_audio_deactivated = true;
did_report_error_last_call = true;
return;
}
win32_check_hr(hr); win32_check_hr(hr);
hr = IAudioClient_GetService(win32_audio_client, &IID_IAudioRenderClient, (void**)&win32_render_client); hr = IAudioClient_GetService(win32_audio_client, &IID_IAudioRenderClient, (void**)&win32_render_client);
@ -1536,14 +1547,8 @@ win32_audio_init() {
DWORD task_index; DWORD task_index;
AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &task_index); AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &task_index);
hr = IAudioClient_GetService(win32_audio_client, &IID_ISimpleAudioVolume, (void**)&win32_audio_volume);
if (SUCCEEDED(hr)) {
hr = ISimpleAudioVolume_SetMasterVolume(win32_audio_volume, 1.0f, 0);
win32_check_hr(hr);
ISimpleAudioVolume_Release(win32_audio_volume);
}
log_info("Successfully initialized default audio device. Channels: %d, sample_rate: %d, bits: %d", audio_output_format.channels, audio_output_format.sample_rate, get_audio_bit_width_byte_size(audio_output_format.bit_width)*8); log_info("Successfully initialized default audio device. Channels: %d, sample_rate: %d, bits: %d", audio_output_format.channels, audio_output_format.sample_rate, get_audio_bit_width_byte_size(audio_output_format.bit_width)*8);
did_report_error_last_call = false;
} }
@ -1574,6 +1579,7 @@ win32_audio_poll_default_device_thread(Thread *t) {
win32_check_hr(hr); win32_check_hr(hr);
if (wcscmp(now_default_id, previous_id) != 0) { if (wcscmp(now_default_id, previous_id) != 0) {
log("Hi");
win32_audio_deactivated = true; win32_audio_deactivated = true;
} }