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
- Avoid playing identical audio at the same time
- Allow audio programming
- Inject mixer proc per player
- 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
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.
Probably just dirty flag
- Optimize
- Spam simd
- Concurrent jobs for players?
- Pool of intermediate buffers (2^)
- Bugs:
- Small fadeout on pause is slightly noisy
- Setting time stamp/progression causes noise (need fade transition like on pause/play)
- End of clip also causes noise if audio clip does not end smoothly
- Bugs / Issues:
- Small fadeout on start/pause is sometimes noisy
- If audio starts/end abrubtly we will get noise. Maybe detect that on load and apply small fade in/out?
- 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
@ -38,12 +37,14 @@
- OS
- Window::bool is_minimized
- don't set window.width & window.height to 0
- Handle monitor change
- Sockets recv, send
- Mouse pointer
- Hide mouse pointer
- Better hash table
- Memory
- In heap allocator, mark pages that fit entirely into free nodes as NOACCESS
- Arenas
- Examples/Guides:
@ -51,13 +52,19 @@
- Z sorting
- Scissor boxing
- Concurrency
- strings
- Rework profiler
- 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
- Concurrency
- Event objects for binary semaphore
- Needs testing:
- Audio format channel conversions
- sample rate downsampling
- 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
- 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
- os_get_number_of_logical_processors()
@ -15,14 +19,35 @@
- os_lock_program_memory_pages
- 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
- Deprecate Rangef stuff
- peek_random()
- Update #Contributions
- Clean up memory barriers in concurrency.c and use volatile instead
- Output d3d11 debug messages before crash on hr fail
- Configurable temporary storage size for new threads
- Deprecated Rangef stuff
- added peek_random()
- Updated #Contributions
- Cleaned up memory barriers in concurrency.c and use volatile instead
- Made hr fails output d3d11 debug messages before crash
- Made temporary storage size runtime-configurable for new threads
- Cleanup temporary storage after thread destroy
- Added Header checking in growing array
- Unfucked linmath alignment
## 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_AVX512 0
#define deprecated(msg)
#define DEPRECATED(proc, msg)
#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);
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");
// 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)
);
}
seed_for_random = 69;
for (u64 i = 0; i < 30000; i++) {
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 y = get_random_float32() * (max_y-min_y) + min_y;
push_z_layer((s32)(y*100));
draw_image(bush_image, v2(x, y), v2(0.1, 0.1), COLOR_WHITE);
pop_z_layer();

View file

@ -1,46 +1,85 @@
/*
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);
Full API:
void growing_array_init_reserve(void **array, u64 block_size_in_bytes, u64 count_to_reserve, Allocator allocator);
void growing_array_init(void **array, u64 block_size_in_bytes, Allocator allocator);
void growing_array_deinit(void **array);
void *growing_array_add_empty(void **array);
void growing_array_add(void **array, void *item);
void growing_array_reserve(void **array, u64 count_to_reserve);
void growing_array_resize(void **array, u64 new_count);
void growing_array_pop(void **array);
void growing_array_clear(void **array);
// Returns -1 if not found
s32 growing_array_find_index_from_left_by_pointer(void **array, void *p);
s32 growing_array_find_index_from_left_by_value(void **array, void *p);
void growing_array_ordered_remove_by_index(void **array, u32 index);
void growing_array_unordered_remove_by_index(void **array, u32 index);
bool growing_array_ordered_remove_by_pointer(void **array, void *p);
bool growing_array_unordered_remove_by_pointer(void **array, void *p);
bool growing_array_ordered_remove_one_by_value(void **array, void *p);
bool growing_array_unordered_remove_one_by_value(void **array, void *p);
u32 growing_array_get_valid_count(void *array);
u32 growing_array_get_allocated_count(void *array);
Usage:
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 {
u32 signature;
u32 valid_count;
u32 allocated_count;
u32 block_size_in_bytes;
Allocator allocator;
} 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
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->valid_count = 0;
header->allocated_count = count_to_reserve;
header->signature = GROWING_ARRAY_SIGNATURE;
*array = header+1;
}
@ -63,12 +103,14 @@ growing_array_init(void **array, u64 block_size_in_bytes, Allocator allocator) {
}
void
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;
dealloc(header->allocator, header);
}
void
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;
if (header->allocated_count >= count_to_reserve) return;
@ -90,6 +132,7 @@ growing_array_reserve(void **array, u64 count_to_reserve) {
void*
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_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) {
assert(check_growing_array_signature(array), "Not a valid growing array");
Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1;
assert(header->valid_count > 0, "No items to pop in growing array");
header->valid_count -= 1;
}
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;
header->valid_count = 0;
}
void
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;
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
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;
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
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;
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
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;
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
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;
return header->valid_count;
}
u32
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;
return header->allocated_count;
}

View file

@ -396,6 +396,11 @@ void os_init(u64 program_memory_capacity) {
#ifndef OOGABOOGA_HEADLESS
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;
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_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}};
DEFINE_GUID(IID_ISimpleAudioVolume,
0x87CE5498, 0x68D6, 0x44E5, 0x92, 0x15, 0x6D, 0xA4, 0x7E, 0xF8, 0x83, 0xD8);
IAudioClient* win32_audio_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
IMMDevice* win32_audio_device = 0;
IMMDeviceEnumerator* win32_device_enumerator = 0;
ISimpleAudioVolume* win32_audio_volume = 0;
Mutex audio_init_mutex;
void
win32_audio_init() {
local_persist bool did_report_error_last_call = false;
win32_audio_client = 0;
win32_render_client = 0;
win32_audio_deactivated = 0;
@ -1502,7 +1506,8 @@ win32_audio_init() {
);
if (hr != S_OK) {
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;
}
output_format = (WAVEFORMATEX*)format_s16;
@ -1518,6 +1523,12 @@ win32_audio_init() {
BUFFER_DURATION_MS*10000ll, 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);
hr = IAudioClient_GetService(win32_audio_client, &IID_IAudioRenderClient, (void**)&win32_render_client);
@ -1536,14 +1547,8 @@ win32_audio_init() {
DWORD 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);
did_report_error_last_call = false;
}
@ -1574,6 +1579,7 @@ win32_audio_poll_default_device_thread(Thread *t) {
win32_check_hr(hr);
if (wcscmp(now_default_id, previous_id) != 0) {
log("Hi");
win32_audio_deactivated = true;
}