v0.01.003 - Mouse pointers, Audio improvement & features, bug fixes
This commit is contained in:
parent
b631b96e62
commit
d89ef01fa6
7 changed files with 150 additions and 61 deletions
23
TODO
23
TODO
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue