Cleanup audio system; put mixer in custom layer; hooks in win32 layer

This commit is contained in:
Allen Webster 2020-11-23 19:32:35 -08:00
parent 4f31b9d5aa
commit 0eecb215ef
13 changed files with 363 additions and 317 deletions

View File

@ -304,19 +304,14 @@ define_api(Arena *arena){
}
{
API_Call *call = api_call(arena, api, "play_clip", "void");
api_param(arena, call, "Audio_Clip", "clip");
api_param(arena, call, "Audio_Control*", "control");
API_Call *call = api_call(arena, api, "set_source_mixer", "void");
api_param(arena, call, "void*", "ctx");
api_param(arena, call, "Audio_Mix_Sources_Function*", "mix_func");
}
{
API_Call *call = api_call(arena, api, "audio_is_playing", "b32");
api_param(arena, call, "Audio_Control*", "control");
}
{
API_Call *call = api_call(arena, api, "audio_stop", "void");
api_param(arena, call, "Audio_Control*", "control");
API_Call *call = api_call(arena, api, "set_destination_mixer", "void");
api_param(arena, call, "Audio_Mix_Destination_Function*", "mix_func");
}
return(api);

View File

@ -1,5 +1,168 @@
////////////////////////////////
// NOTE(allen): Load Clip
// NOTE(allen): Default Mixer Helpers
// TODO(allen): intrinsics wrappers
#include <intrin.h>
function u32
AtomicAddU32AndReturnOriginal(u32 volatile *Value, u32 Addend)
{
// NOTE(casey): Returns the original value _prior_ to adding
u32 Result = _InterlockedExchangeAdd((long volatile*)Value, (long)Addend);
return(Result);
}
function void
def_audio_begin_ticket_mutex(Audio_System *Crunky)
{
u32 Ticket = AtomicAddU32AndReturnOriginal(&Crunky->ticket, 1);
while(Ticket != Crunky->serving) {_mm_pause();}
}
function void
def_audio_end_ticket_mutex(Audio_System *Crunky)
{
AtomicAddU32AndReturnOriginal(&Crunky->serving, 1);
}
////////////////////////////////
// NOTE(allen): Default Mixer
global Audio_System def_audio_system = {};
function void
def_audio_init(void){
block_zero_struct(&def_audio_system);
system_set_source_mixer(&def_audio_system, def_audio_mix_sources);
system_set_destination_mixer(def_audio_mix_destination);
}
function void
def_audio_play_clip(Audio_Clip clip, Audio_Control *control){
clip.control = control;
Audio_System *Crunky = &def_audio_system;
def_audio_begin_ticket_mutex(Crunky);
if (Crunky->pending_clip_count < ArrayCount(Crunky->pending_clips))
{
Crunky->pending_clips[Crunky->pending_clip_count++] = clip;
}
def_audio_end_ticket_mutex(Crunky);
}
internal b32
def_audio_is_playing(Audio_Control *control){
Audio_System *Crunky = &def_audio_system;
b32 result = (Crunky->generation - control->generation < 2);
return(result);
}
internal void
def_audio_stop(Audio_Control *control){
Audio_System *Crunky = &def_audio_system;
def_audio_begin_ticket_mutex(Crunky);
Audio_Clip *clip = Crunky->playing_clips;
for(u32 i = 0;
i < ArrayCount(Crunky->playing_clips);
i += 1, clip += 1){
if (clip->control == control){
clip->at_sample_index = clip->sample_count;
clip->control = 0;
}
}
control->loop = false;
def_audio_end_ticket_mutex(Crunky);
}
function void
def_audio_mix_sources(void *ctx, f32 *mix_buffer, u32 sample_count){
Audio_System *Crunky = (Audio_System*)ctx;
def_audio_begin_ticket_mutex(Crunky);
// NOTE(casey): Move pending sounds into the playing list
{
Crunky->generation += 1;
u32 PendIndex = 0;
Audio_Clip *clip = Crunky->playing_clips;
for(u32 DestIndex = 0;
(DestIndex < ArrayCount(Crunky->playing_clips)) && (PendIndex < Crunky->pending_clip_count);
DestIndex += 1, clip += 1)
{
if (clip->at_sample_index == clip->sample_count)
{
Audio_Control *control = clip->control;
if (control == 0 || !control->loop){
*clip = Crunky->pending_clips[PendIndex++];
}
}
}
Crunky->pending_clip_count = 0;
}
def_audio_end_ticket_mutex(Crunky);
// NOTE(casey): Mix all sounds into the output buffer
{
Audio_Clip *clip = Crunky->playing_clips;
for(u32 SoundIndex = 0;
SoundIndex < ArrayCount(Crunky->playing_clips);
SoundIndex += 1, clip += 1)
{
// NOTE(allen): Determine starting point
Audio_Control *control = clip->control;
if (control != 0 && control->loop && clip->at_sample_index == clip->sample_count){
clip->at_sample_index = 0;
}
u32 base_sample_index = clip->at_sample_index;
// NOTE(casey): Determine how many samples are left to play in this
// sound (possible none)
u32 SamplesToMix = clamp_top((clip->sample_count - clip->at_sample_index), sample_count);
clip->at_sample_index += SamplesToMix;
// NOTE(casey): Load the volume out of the control if there is one,
// and if there is, update the generation and sample index so
// external controllers can take action
f32 LeftVol = clip->channel_volume[0];
f32 RightVol = clip->channel_volume[1];
if(SamplesToMix && control != 0)
{
LeftVol *= control->channel_volume[0];
RightVol *= control->channel_volume[1];
control->generation = Crunky->generation;
control->last_played_sample_index = clip->at_sample_index;
}
// NOTE(casey): Mix samples
for(u32 SampleIndex = 0;
SampleIndex < SamplesToMix;
++SampleIndex)
{
u32 src_index = 2*(base_sample_index + SampleIndex);
f32 Left = LeftVol *(f32)clip->samples[src_index + 0];
f32 Right = RightVol*(f32)clip->samples[src_index + 1];
u32 dst_index = 2*SampleIndex;
mix_buffer[dst_index + 0] += Left;
mix_buffer[dst_index + 1] += Right;
}
}
}
}
function void
def_audio_mix_destination(i16 *dst, f32 *src, u32 sample_count){
u32 opl = sample_count*2;
for(u32 i = 0; i < opl; i += 1){
f32 sample = src[i];
f32 sat_sample = clamp(-32768.f, sample, 32767.f);
dst[i] = (i16)sat_sample;
}
}
////////////////////////////////
// NOTE(allen): Loading Clip
#if !defined(FCODER_SKIP_WAV)
#define FCODER_SKIP_WAV

View File

@ -4,8 +4,52 @@
#define FCODER_AUDIO_H
////////////////////////////////
// NOTE(allen): Load Clip
// NOTE(allen): Default Mixer Types
struct Audio_Control{
volatile f32 channel_volume[2];
volatile u32 generation;
volatile u32 last_played_sample_index;
volatile b32 loop;
};
struct Audio_Clip{
i16 *samples;
Audio_Control *control;
f32 channel_volume[2];
u32 sample_count;
u32 at_sample_index;
};
struct Audio_System{
volatile u32 quit;
volatile u32 ticket;
volatile u32 serving;
volatile u32 generation;
Audio_Clip playing_clips[64];
// NOTE(casey): Requests to play sounds are written to a pending array to avoid long locking
volatile u32 pending_clip_count;
Audio_Clip pending_clips[64];
};
////////////////////////////////
// NOTE(allen): Default Mixer
function void def_audio_init(void);
function void def_audio_play_clip(Audio_Clip clip, Audio_Control *control);
function b32 def_audio_is_playing(Audio_Control *control);
function void def_audio_stop(Audio_Control *control);
function void def_audio_mix_sources(void *ctx, f32 *mix_buffer, u32 sample_count);
function void def_audio_mix_destination(i16 *dst, f32 *src, u32 sample_count);
////////////////////////////////
// NOTE(allen): Loading Clip
function Audio_Clip audio_clip_from_wav_data(String_Const_u8 data);
function Audio_Clip audio_clip_from_wav_file_name(char *file_name);
#endif //4CODER_AUDIO_H

View File

@ -20,12 +20,14 @@ CUSTOM_DOC("Default command for responding to a startup event")
}
{
def_audio_init();
Audio_Clip test_clip = audio_clip_from_wav_file_name("W:\\4ed\\audio_test\\raygun_zap.wav");
local_persist Audio_Control test_control = {};
test_control.channel_volume[0] = 1.f;
test_control.channel_volume[1] = 1.f;
system_play_clip(test_clip, &test_control);
def_audio_play_clip(test_clip, &test_control);
}
}

View File

@ -208,60 +208,6 @@ CUSTOM_DOC("Example of query_user_string and query_user_number")
}
}
CUSTOM_COMMAND_SIG(test_the_new_api)
CUSTOM_DOC("If you are reading this I forgot to delete this test, please let me know")
{
Query_Bar_Group group(app);
Query_Bar bar = {};
bar.prompt = SCu8("Testing ... ");
if (!start_query_bar(app, &bar, 0)){
return;
}
Input_Event events[10];
i32 count = 0;
User_Input in = {};
for (;;) {
in = get_next_input(app, EventProperty_AnyKey, 0);
if (in.abort){
return;
}
events[count] = in.event;
count += 1;
if (!event_is_dead_key(&in.event)) {
break;
}
}
u64 codepoints[10] = {};
i32 index = 0;
for (Input_Event event_text = event_next_text_event(&in.event);
event_text.kind != InputEventKind_None;
event_text = event_next_text_event(&event_text)){
String_Const_u8 writable = to_writable(&event_text);
if (writable.size) {
codepoints[index] = utf8_consume(writable.str, writable.size).codepoint;
index += 1;
}
}
Scratch_Block scratch(app);
for (i32 i = 0; i < count; i += 1){
String_Const_u8 string = stringize_keyboard_event(scratch, &events[i]);
print_message(app, string);
}
for (i32 i = 0; i < index; i += 1){
String_Const_u8 string = push_u8_stringf(scratch, "%llu\n", codepoints[i]);
print_message(app, string);
}
}
global Audio_Control the_music_control = {};
CUSTOM_COMMAND_SIG(music_start)
@ -274,18 +220,18 @@ CUSTOM_DOC("Starts the music.")
the_music_clip = audio_clip_from_wav_file_name("W:\\4ed\\audio_test\\chtulthu.wav");
}
if (!system_audio_is_playing(&the_music_control)){
if (!def_audio_is_playing(&the_music_control)){
the_music_control.loop = true;
the_music_control.channel_volume[0] = 1.f;
the_music_control.channel_volume[1] = 1.f;
system_play_clip(the_music_clip, &the_music_control);
def_audio_play_clip(the_music_clip, &the_music_control);
}
}
CUSTOM_COMMAND_SIG(music_stop)
CUSTOM_DOC("Stops the music.")
{
system_audio_stop(&the_music_control);
def_audio_stop(&the_music_control);
}
CUSTOM_COMMAND_SIG(hit_sfx)
@ -302,11 +248,11 @@ CUSTOM_DOC("Play the hit sound effect")
local_persist Audio_Control controls[8] = {};
Audio_Control *control = &controls[index%8];
if (!system_audio_is_playing(control)){
if (!def_audio_is_playing(control)){
control->loop = false;
control->channel_volume[0] = 1.f;
control->channel_volume[1] = 1.f;
system_play_clip(the_hit_clip, control);
def_audio_play_clip(the_hit_clip, control);
index += 1;
}
}

View File

@ -789,36 +789,10 @@ struct Process_State{
////////////////////////////////
api(custom)
struct Audio_Control{
volatile f32 channel_volume[2];
volatile u32 generation;
volatile u32 last_played_sample_index;
volatile b32 loop;
};
api(custom)
struct Audio_Clip{
i16 *samples;
Audio_Control *control;
f32 channel_volume[2];
u32 sample_count;
u32 at_sample_index;
};
api(custom)
struct Audio_System{
volatile u32 quit;
volatile u32 ticket;
volatile u32 serving;
volatile u32 generation;
Audio_Clip playing_clips[64];
// NOTE(casey): Requests to play sounds are written to a pending array to avoid long locking
volatile u32 pending_clip_count;
Audio_Clip pending_clips[64];
};
// NOTE(allen): buffers are allocate with:
// array_count = channel_count*sample_count
// channel_count = 2
typedef void Audio_Mix_Sources_Function(void *ctx, f32 *buffer, u32 sample_count);
typedef void Audio_Mix_Destination_Function(i16 *dst, f32 *src, u32 sample_count);
#endif

View File

@ -2,7 +2,7 @@
#define command_id(c) (fcoder_metacmd_ID_##c)
#define command_metadata(c) (&fcoder_metacmd_table[command_id(c)])
#define command_metadata_by_id(id) (&fcoder_metacmd_table[id])
#define command_one_past_last_id 251
#define command_one_past_last_id 250
#if defined(CUSTOM_COMMAND_SIG)
#define PROC_LINKS(x,y) x
#else
@ -227,7 +227,6 @@ CUSTOM_COMMAND_SIG(snippet_lister);
CUSTOM_COMMAND_SIG(string_repeat);
CUSTOM_COMMAND_SIG(suppress_mouse);
CUSTOM_COMMAND_SIG(swap_panels);
CUSTOM_COMMAND_SIG(test_the_new_api);
CUSTOM_COMMAND_SIG(theme_lister);
CUSTOM_COMMAND_SIG(to_lowercase);
CUSTOM_COMMAND_SIG(to_uppercase);
@ -272,7 +271,7 @@ char *source_name;
i32 source_name_len;
i32 line_number;
};
static Command_Metadata fcoder_metacmd_table[251] = {
static Command_Metadata fcoder_metacmd_table[250] = {
{ PROC_LINKS(allow_mouse, 0), false, "allow_mouse", 11, "Shows the mouse and causes all mouse input to be processed normally.", 68, "W:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 485 },
{ PROC_LINKS(auto_indent_line_at_cursor, 0), false, "auto_indent_line_at_cursor", 26, "Auto-indents the line on which the cursor sits.", 47, "W:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 417 },
{ PROC_LINKS(auto_indent_range, 0), false, "auto_indent_range", 17, "Auto-indents the range between the cursor and the mark.", 55, "W:\\4ed\\code\\custom\\4coder_auto_indent.cpp", 41, 427 },
@ -310,8 +309,8 @@ static Command_Metadata fcoder_metacmd_table[251] = {
{ PROC_LINKS(decrease_face_size, 0), false, "decrease_face_size", 18, "Decrease the size of the face used by the current buffer.", 57, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 757 },
{ PROC_LINKS(default_file_externally_modified, 0), false, "default_file_externally_modified", 32, "Notes the external modification of attached files by printing a message.", 72, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 2062 },
{ PROC_LINKS(default_startup, 0), false, "default_startup", 15, "Default command for responding to a startup event", 49, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 7 },
{ PROC_LINKS(default_try_exit, 0), false, "default_try_exit", 16, "Default command for responding to a try-exit event", 50, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 32 },
{ PROC_LINKS(default_view_input_handler, 0), false, "default_view_input_handler", 26, "Input consumption loop for default view behavior", 48, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 76 },
{ PROC_LINKS(default_try_exit, 0), false, "default_try_exit", 16, "Default command for responding to a try-exit event", 50, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 34 },
{ PROC_LINKS(default_view_input_handler, 0), false, "default_view_input_handler", 26, "Input consumption loop for default view behavior", 48, "W:\\4ed\\code\\custom\\4coder_default_hooks.cpp", 43, 78 },
{ PROC_LINKS(delete_alpha_numeric_boundary, 0), false, "delete_alpha_numeric_boundary", 29, "Delete characters between the cursor position and the first alphanumeric boundary to the right.", 95, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 161 },
{ PROC_LINKS(delete_char, 0), false, "delete_char", 11, "Deletes the character to the right of the cursor.", 49, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 79 },
{ PROC_LINKS(delete_current_scope, 0), false, "delete_current_scope", 20, "Deletes the braces surrounding the currently selected scope. Leaves the contents within the scope.", 99, "W:\\4ed\\code\\custom\\4coder_scope_commands.cpp", 44, 112 },
@ -338,7 +337,7 @@ static Command_Metadata fcoder_metacmd_table[251] = {
{ PROC_LINKS(goto_prev_jump_no_skips, 0), false, "goto_prev_jump_no_skips", 23, "If a buffer containing jump locations has been locked in, goes to the previous jump in the buffer, and does not skip sub jump locations.", 136, "W:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 511 },
{ PROC_LINKS(hide_filebar, 0), false, "hide_filebar", 12, "Sets the current view to hide it's filebar.", 43, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 704 },
{ PROC_LINKS(hide_scrollbar, 0), false, "hide_scrollbar", 14, "Sets the current view to hide it's scrollbar.", 45, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 690 },
{ PROC_LINKS(hit_sfx, 0), false, "hit_sfx", 7, "Play the hit sound effect", 25, "W:\\4ed\\code\\custom\\4coder_examples.cpp", 38, 291 },
{ PROC_LINKS(hit_sfx, 0), false, "hit_sfx", 7, "Play the hit sound effect", 25, "W:\\4ed\\code\\custom\\4coder_examples.cpp", 38, 237 },
{ PROC_LINKS(hms_demo_tutorial, 0), false, "hms_demo_tutorial", 17, "Tutorial for built in 4coder bindings and features.", 51, "W:\\4ed\\code\\custom\\4coder_tutorial.cpp", 38, 869 },
{ PROC_LINKS(if0_off, 0), false, "if0_off", 7, "Surround the range between the cursor and mark with an '#if 0' and an '#endif'", 78, "W:\\4ed\\code\\custom\\4coder_combined_write_commands.cpp", 53, 70 },
{ PROC_LINKS(if_read_only_goto_position, 0), false, "if_read_only_goto_position", 26, "If the buffer in the active view is writable, inserts a character, otherwise performs goto_jump_at_cursor.", 106, "W:\\4ed\\code\\custom\\4coder_jump_sticky.cpp", 41, 564 },
@ -413,8 +412,8 @@ static Command_Metadata fcoder_metacmd_table[251] = {
{ PROC_LINKS(multi_paste, 0), false, "multi_paste", 11, "Paste multiple entries from the clipboard at once", 49, "W:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 229 },
{ PROC_LINKS(multi_paste_interactive, 0), false, "multi_paste_interactive", 23, "Paste multiple lines from the clipboard history, controlled with arrow keys", 75, "W:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 371 },
{ PROC_LINKS(multi_paste_interactive_quick, 0), false, "multi_paste_interactive_quick", 29, "Paste multiple lines from the clipboard history, controlled by inputing the number of lines to paste", 100, "W:\\4ed\\code\\custom\\4coder_clipboard.cpp", 39, 380 },
{ PROC_LINKS(music_start, 0), false, "music_start", 11, "Starts the music.", 17, "W:\\4ed\\code\\custom\\4coder_examples.cpp", 38, 267 },
{ PROC_LINKS(music_stop, 0), false, "music_stop", 10, "Stops the music.", 16, "W:\\4ed\\code\\custom\\4coder_examples.cpp", 38, 285 },
{ PROC_LINKS(music_start, 0), false, "music_start", 11, "Starts the music.", 17, "W:\\4ed\\code\\custom\\4coder_examples.cpp", 38, 213 },
{ PROC_LINKS(music_stop, 0), false, "music_stop", 10, "Stops the music.", 16, "W:\\4ed\\code\\custom\\4coder_examples.cpp", 38, 231 },
{ PROC_LINKS(open_all_code, 0), false, "open_all_code", 13, "Open all code in the current directory. File types are determined by extensions. An extension is considered code based on the extensions specified in 4coder.config.", 164, "W:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 850 },
{ PROC_LINKS(open_all_code_recursive, 0), false, "open_all_code_recursive", 23, "Works as open_all_code but also runs in all subdirectories.", 59, "W:\\4ed\\code\\custom\\4coder_project_commands.cpp", 46, 856 },
{ PROC_LINKS(open_file_in_quotes, 0), false, "open_file_in_quotes", 19, "Reads a filename from surrounding '\"' characters and attempts to open the corresponding file.", 94, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1574 },
@ -491,7 +490,6 @@ static Command_Metadata fcoder_metacmd_table[251] = {
{ PROC_LINKS(string_repeat, 0), false, "string_repeat", 13, "Example of query_user_string and query_user_number", 50, "W:\\4ed\\code\\custom\\4coder_examples.cpp", 38, 179 },
{ PROC_LINKS(suppress_mouse, 0), false, "suppress_mouse", 14, "Hides the mouse and causes all mosue input (clicks, position, wheel) to be ignored.", 83, "W:\\4ed\\code\\custom\\4coder_default_framework.cpp", 47, 479 },
{ PROC_LINKS(swap_panels, 0), false, "swap_panels", 11, "Swaps the active panel with it's sibling.", 41, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 1682 },
{ PROC_LINKS(test_the_new_api, 0), false, "test_the_new_api", 16, "If you are reading this I forgot to delete this test, please let me know", 72, "W:\\4ed\\code\\custom\\4coder_examples.cpp", 38, 212 },
{ PROC_LINKS(theme_lister, 0), true, "theme_lister", 12, "Opens an interactive list of all registered themes.", 51, "W:\\4ed\\code\\custom\\4coder_lists.cpp", 35, 784 },
{ PROC_LINKS(to_lowercase, 0), false, "to_lowercase", 12, "Converts all ascii text in the range between the cursor and the mark to lowercase.", 82, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 567 },
{ PROC_LINKS(to_uppercase, 0), false, "to_uppercase", 12, "Converts all ascii text in the range between the cursor and the mark to uppercase.", 82, "W:\\4ed\\code\\custom\\4coder_base_commands.cpp", 43, 554 },
@ -743,37 +741,36 @@ static i32 fcoder_metacmd_ID_snippet_lister = 214;
static i32 fcoder_metacmd_ID_string_repeat = 215;
static i32 fcoder_metacmd_ID_suppress_mouse = 216;
static i32 fcoder_metacmd_ID_swap_panels = 217;
static i32 fcoder_metacmd_ID_test_the_new_api = 218;
static i32 fcoder_metacmd_ID_theme_lister = 219;
static i32 fcoder_metacmd_ID_to_lowercase = 220;
static i32 fcoder_metacmd_ID_to_uppercase = 221;
static i32 fcoder_metacmd_ID_toggle_filebar = 222;
static i32 fcoder_metacmd_ID_toggle_fps_meter = 223;
static i32 fcoder_metacmd_ID_toggle_fullscreen = 224;
static i32 fcoder_metacmd_ID_toggle_highlight_enclosing_scopes = 225;
static i32 fcoder_metacmd_ID_toggle_highlight_line_at_cursor = 226;
static i32 fcoder_metacmd_ID_toggle_line_numbers = 227;
static i32 fcoder_metacmd_ID_toggle_line_wrap = 228;
static i32 fcoder_metacmd_ID_toggle_mouse = 229;
static i32 fcoder_metacmd_ID_toggle_paren_matching_helper = 230;
static i32 fcoder_metacmd_ID_toggle_show_whitespace = 231;
static i32 fcoder_metacmd_ID_toggle_virtual_whitespace = 232;
static i32 fcoder_metacmd_ID_tutorial_maximize = 233;
static i32 fcoder_metacmd_ID_tutorial_minimize = 234;
static i32 fcoder_metacmd_ID_uncomment_line = 235;
static i32 fcoder_metacmd_ID_undo = 236;
static i32 fcoder_metacmd_ID_undo_all_buffers = 237;
static i32 fcoder_metacmd_ID_view_buffer_other_panel = 238;
static i32 fcoder_metacmd_ID_view_jump_list_with_lister = 239;
static i32 fcoder_metacmd_ID_word_complete = 240;
static i32 fcoder_metacmd_ID_word_complete_drop_down = 241;
static i32 fcoder_metacmd_ID_write_block = 242;
static i32 fcoder_metacmd_ID_write_hack = 243;
static i32 fcoder_metacmd_ID_write_note = 244;
static i32 fcoder_metacmd_ID_write_space = 245;
static i32 fcoder_metacmd_ID_write_text_and_auto_indent = 246;
static i32 fcoder_metacmd_ID_write_text_input = 247;
static i32 fcoder_metacmd_ID_write_todo = 248;
static i32 fcoder_metacmd_ID_write_underscore = 249;
static i32 fcoder_metacmd_ID_write_zero_struct = 250;
static i32 fcoder_metacmd_ID_theme_lister = 218;
static i32 fcoder_metacmd_ID_to_lowercase = 219;
static i32 fcoder_metacmd_ID_to_uppercase = 220;
static i32 fcoder_metacmd_ID_toggle_filebar = 221;
static i32 fcoder_metacmd_ID_toggle_fps_meter = 222;
static i32 fcoder_metacmd_ID_toggle_fullscreen = 223;
static i32 fcoder_metacmd_ID_toggle_highlight_enclosing_scopes = 224;
static i32 fcoder_metacmd_ID_toggle_highlight_line_at_cursor = 225;
static i32 fcoder_metacmd_ID_toggle_line_numbers = 226;
static i32 fcoder_metacmd_ID_toggle_line_wrap = 227;
static i32 fcoder_metacmd_ID_toggle_mouse = 228;
static i32 fcoder_metacmd_ID_toggle_paren_matching_helper = 229;
static i32 fcoder_metacmd_ID_toggle_show_whitespace = 230;
static i32 fcoder_metacmd_ID_toggle_virtual_whitespace = 231;
static i32 fcoder_metacmd_ID_tutorial_maximize = 232;
static i32 fcoder_metacmd_ID_tutorial_minimize = 233;
static i32 fcoder_metacmd_ID_uncomment_line = 234;
static i32 fcoder_metacmd_ID_undo = 235;
static i32 fcoder_metacmd_ID_undo_all_buffers = 236;
static i32 fcoder_metacmd_ID_view_buffer_other_panel = 237;
static i32 fcoder_metacmd_ID_view_jump_list_with_lister = 238;
static i32 fcoder_metacmd_ID_word_complete = 239;
static i32 fcoder_metacmd_ID_word_complete_drop_down = 240;
static i32 fcoder_metacmd_ID_write_block = 241;
static i32 fcoder_metacmd_ID_write_hack = 242;
static i32 fcoder_metacmd_ID_write_note = 243;
static i32 fcoder_metacmd_ID_write_space = 244;
static i32 fcoder_metacmd_ID_write_text_and_auto_indent = 245;
static i32 fcoder_metacmd_ID_write_text_input = 246;
static i32 fcoder_metacmd_ID_write_todo = 247;
static i32 fcoder_metacmd_ID_write_underscore = 248;
static i32 fcoder_metacmd_ID_write_zero_struct = 249;
#endif

View File

@ -54,9 +54,8 @@ vtable->set_fullscreen = system_set_fullscreen;
vtable->is_fullscreen = system_is_fullscreen;
vtable->get_keyboard_modifiers = system_get_keyboard_modifiers;
vtable->set_key_mode = system_set_key_mode;
vtable->play_clip = system_play_clip;
vtable->audio_is_playing = system_audio_is_playing;
vtable->audio_stop = system_audio_stop;
vtable->set_source_mixer = system_set_source_mixer;
vtable->set_destination_mixer = system_set_destination_mixer;
}
#if defined(DYNAMIC_LINK_API)
function void
@ -115,9 +114,8 @@ system_set_fullscreen = vtable->set_fullscreen;
system_is_fullscreen = vtable->is_fullscreen;
system_get_keyboard_modifiers = vtable->get_keyboard_modifiers;
system_set_key_mode = vtable->set_key_mode;
system_play_clip = vtable->play_clip;
system_audio_is_playing = vtable->audio_is_playing;
system_audio_stop = vtable->audio_stop;
system_set_source_mixer = vtable->set_source_mixer;
system_set_destination_mixer = vtable->set_destination_mixer;
}
#undef DYNAMIC_LINK_API
#endif

View File

@ -52,9 +52,8 @@
#define system_is_fullscreen_sig() b32 system_is_fullscreen(void)
#define system_get_keyboard_modifiers_sig() Input_Modifier_Set system_get_keyboard_modifiers(Arena* arena)
#define system_set_key_mode_sig() void system_set_key_mode(Key_Mode mode)
#define system_play_clip_sig() void system_play_clip(Audio_Clip clip, Audio_Control* control)
#define system_audio_is_playing_sig() b32 system_audio_is_playing(Audio_Control* control)
#define system_audio_stop_sig() void system_audio_stop(Audio_Control* control)
#define system_set_source_mixer_sig() void system_set_source_mixer(void* ctx, Audio_Mix_Sources_Function* mix_func)
#define system_set_destination_mixer_sig() void system_set_destination_mixer(Audio_Mix_Destination_Function* mix_func)
typedef String_Const_u8 system_get_path_type(Arena* arena, System_Path_Code path_code);
typedef String_Const_u8 system_get_canonical_type(Arena* arena, String_Const_u8 name);
typedef File_List system_get_file_list_type(Arena* arena, String_Const_u8 directory);
@ -109,9 +108,8 @@ typedef b32 system_set_fullscreen_type(b32 full_screen);
typedef b32 system_is_fullscreen_type(void);
typedef Input_Modifier_Set system_get_keyboard_modifiers_type(Arena* arena);
typedef void system_set_key_mode_type(Key_Mode mode);
typedef void system_play_clip_type(Audio_Clip clip, Audio_Control* control);
typedef b32 system_audio_is_playing_type(Audio_Control* control);
typedef void system_audio_stop_type(Audio_Control* control);
typedef void system_set_source_mixer_type(void* ctx, Audio_Mix_Sources_Function* mix_func);
typedef void system_set_destination_mixer_type(Audio_Mix_Destination_Function* mix_func);
struct API_VTable_system{
system_get_path_type *get_path;
system_get_canonical_type *get_canonical;
@ -167,9 +165,8 @@ system_set_fullscreen_type *set_fullscreen;
system_is_fullscreen_type *is_fullscreen;
system_get_keyboard_modifiers_type *get_keyboard_modifiers;
system_set_key_mode_type *set_key_mode;
system_play_clip_type *play_clip;
system_audio_is_playing_type *audio_is_playing;
system_audio_stop_type *audio_stop;
system_set_source_mixer_type *set_source_mixer;
system_set_destination_mixer_type *set_destination_mixer;
};
#if defined(STATIC_LINK_API)
internal String_Const_u8 system_get_path(Arena* arena, System_Path_Code path_code);
@ -226,9 +223,8 @@ internal b32 system_set_fullscreen(b32 full_screen);
internal b32 system_is_fullscreen(void);
internal Input_Modifier_Set system_get_keyboard_modifiers(Arena* arena);
internal void system_set_key_mode(Key_Mode mode);
internal void system_play_clip(Audio_Clip clip, Audio_Control* control);
internal b32 system_audio_is_playing(Audio_Control* control);
internal void system_audio_stop(Audio_Control* control);
internal void system_set_source_mixer(void* ctx, Audio_Mix_Sources_Function* mix_func);
internal void system_set_destination_mixer(Audio_Mix_Destination_Function* mix_func);
#undef STATIC_LINK_API
#elif defined(DYNAMIC_LINK_API)
global system_get_path_type *system_get_path = 0;
@ -285,8 +281,7 @@ global system_set_fullscreen_type *system_set_fullscreen = 0;
global system_is_fullscreen_type *system_is_fullscreen = 0;
global system_get_keyboard_modifiers_type *system_get_keyboard_modifiers = 0;
global system_set_key_mode_type *system_set_key_mode = 0;
global system_play_clip_type *system_play_clip = 0;
global system_audio_is_playing_type *system_audio_is_playing = 0;
global system_audio_stop_type *system_audio_stop = 0;
global system_set_source_mixer_type *system_set_source_mixer = 0;
global system_set_destination_mixer_type *system_set_destination_mixer = 0;
#undef DYNAMIC_LINK_API
#endif

View File

@ -246,17 +246,13 @@ API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("set_ke
api_param(arena, call, "Key_Mode", "mode");
}
{
API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("play_clip"), string_u8_litexpr("void"), string_u8_litexpr(""));
api_param(arena, call, "Audio_Clip", "clip");
api_param(arena, call, "Audio_Control*", "control");
API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("set_source_mixer"), string_u8_litexpr("void"), string_u8_litexpr(""));
api_param(arena, call, "void*", "ctx");
api_param(arena, call, "Audio_Mix_Sources_Function*", "mix_func");
}
{
API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("audio_is_playing"), string_u8_litexpr("b32"), string_u8_litexpr(""));
api_param(arena, call, "Audio_Control*", "control");
}
{
API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("audio_stop"), string_u8_litexpr("void"), string_u8_litexpr(""));
api_param(arena, call, "Audio_Control*", "control");
API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("set_destination_mixer"), string_u8_litexpr("void"), string_u8_litexpr(""));
api_param(arena, call, "Audio_Mix_Destination_Function*", "mix_func");
}
return(result);
}

View File

@ -52,6 +52,5 @@ api(system) function b32 set_fullscreen(b32 full_screen);
api(system) function b32 is_fullscreen(void);
api(system) function Input_Modifier_Set get_keyboard_modifiers(Arena* arena);
api(system) function void set_key_mode(Key_Mode mode);
api(system) function void play_clip(Audio_Clip clip, Audio_Control* control);
api(system) function b32 audio_is_playing(Audio_Control* control);
api(system) function void audio_stop(Audio_Control* control);
api(system) function void set_source_mixer(void* ctx, Audio_Mix_Sources_Function* mix_func);
api(system) function void set_destination_mixer(Audio_Mix_Destination_Function* mix_func);

View File

@ -179,9 +179,12 @@ struct Win32_Vars{
HWND window_handle;
f32 screen_scale_factor;
Audio_System audio_system;
DWORD audio_thread_id;
void *volatile audio_mix_ctx;
Audio_Mix_Sources_Function *volatile audio_mix_sources;
Audio_Mix_Destination_Function *volatile audio_mix_destination;
f64 count_per_usecond;
b32 first;
i32 running_cli;
@ -1812,7 +1815,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
win32_resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top);
// NOTE(allen): Audio Init
win32vars.audio_thread_id = win32_audio_init(&win32vars.audio_system);
win32vars.audio_thread_id = win32_audio_init();
// NOTE(allen): Misc Init
if (!AddClipboardFormatListener(win32vars.window_handle)){

View File

@ -1,164 +1,96 @@
////////////////////////////////
// NOTE(allen): Win32 Audio Helpers
// NOTE(allen): Quick Mutex
// TODO(allen): intrinsics wrappers
#include <intrin.h>
function u32
AtomicAddU32AndReturnOriginal(u32 volatile *Value, u32 Addend)
{
// NOTE(casey): Returns the original value _prior_ to adding
u32 Result = _InterlockedExchangeAdd(Value, Addend);
u32 Result = _InterlockedExchangeAdd((long volatile*)Value, (long)Addend);
return(Result);
}
global volatile u32 win32_audio_ticket = 0;
global volatile u32 win32_audio_serving = 0;
function void
win32_begin_ticket_mutex(Audio_System *Crunky)
win32_audio_begin_ticket_mutex(void)
{
u32 Ticket = AtomicAddU32AndReturnOriginal(&Crunky->ticket, 1);
while(Ticket != Crunky->serving) {_mm_pause();}
u32 Ticket = AtomicAddU32AndReturnOriginal(&win32_audio_ticket, 1);
while(Ticket != win32_audio_serving) {_mm_pause();}
}
function void
win32_audio_end_ticket_mutex(void)
{
AtomicAddU32AndReturnOriginal(&win32_audio_serving, 1);
}
////////////////////////////////
// NOTE(allen): Fallback Mixers
function void
win32_default_mix_sources(void *ctx, f32 *mix_buffer, u32 sample_count){
}
function void
win32_end_ticket_mutex(Audio_System *Crunky)
{
AtomicAddU32AndReturnOriginal(&Crunky->serving, 1);
win32_default_mix_destination(i16 *dst, f32 *src, u32 sample_count){
u32 opl = sample_count*2;
for(u32 i = 0; i < sample_count; i += 1){
dst[i] = (i16)src[i];
}
}
////////////////////////////////
// NOTE(allen): Win32 Audio System API
internal
system_play_clip_sig(){
clip.control = control;
Audio_System *Crunky = &win32vars.audio_system;
win32_begin_ticket_mutex(Crunky);
if (Crunky->pending_clip_count < ArrayCount(Crunky->pending_clips))
{
Crunky->pending_clips[Crunky->pending_clip_count++] = clip;
}
win32_end_ticket_mutex(Crunky);
system_set_source_mixer_sig(){
win32_audio_begin_ticket_mutex();
win32vars.audio_mix_ctx = ctx;
win32vars.audio_mix_sources = mix_func;
win32_audio_end_ticket_mutex();
}
internal
system_audio_is_playing_sig(){
Audio_System *Crunky = (Audio_System *)&win32vars.audio_system;
b32 result = (Crunky->generation - control->generation < 2);
return(result);
}
internal
system_audio_stop_sig(){
Audio_System *Crunky = (Audio_System *)&win32vars.audio_system;
win32_begin_ticket_mutex(Crunky);
Audio_Clip *clip = Crunky->playing_clips;
for(u32 i = 0;
i < ArrayCount(Crunky->playing_clips);
i += 1, clip += 1){
if (clip->control == control){
clip->at_sample_index = clip->sample_count;
}
}
control->loop = false;
win32_end_ticket_mutex(Crunky);
system_set_destination_mixer_sig(){
win32_audio_begin_ticket_mutex();
win32vars.audio_mix_destination = mix_func;
win32_audio_end_ticket_mutex();
}
////////////////////////////////
// NOTE(allen): Win32 Audio Loop
function void
win32_mix_audio(Audio_System *Crunky, u32 SampleCount, i16 *Dest, void *mix_buffer_memory){
// NOTE(casey): Clear the output buffer
u32 MixBufferSize = SampleCount*2*sizeof(f32);
f32 *MixBuffer = (f32 *)mix_buffer_memory;
memset(MixBuffer, 0, MixBufferSize);
win32_begin_ticket_mutex(Crunky);
// NOTE(casey): Move pending sounds into the playing list
{
Crunky->generation += 1;
u32 PendIndex = 0;
Audio_Clip *clip = Crunky->playing_clips;
for(u32 DestIndex = 0;
(DestIndex < ArrayCount(Crunky->playing_clips)) && (PendIndex < Crunky->pending_clip_count);
DestIndex += 1, clip += 1)
{
if (clip->at_sample_index == clip->sample_count)
{
Audio_Control *control = clip->control;
if (control == 0 || !control->loop){
*clip = Crunky->pending_clips[PendIndex++];
}
}
}
Crunky->pending_clip_count = 0;
}
win32_end_ticket_mutex(Crunky);
// NOTE(casey): Mix all sounds into the output buffer
{
Audio_Clip *clip = Crunky->playing_clips;
for(u32 SoundIndex = 0;
SoundIndex < ArrayCount(Crunky->playing_clips);
SoundIndex += 1, clip += 1)
{
Audio_Control *control = clip->control;
if (control != 0 && control->loop && clip->at_sample_index == clip->sample_count){
clip->at_sample_index = 0;
}
// NOTE(casey): Determine how many samples are left to play in this
// sound (possible none)
u32 SamplesToMix = Min((clip->sample_count - clip->at_sample_index), SampleCount);
clip->at_sample_index += SamplesToMix;
// NOTE(casey): Load the volume out of the control if there is one,
// and if there is, update the generation and sample index so
// external controllers can take action
f32 LeftVol = clip->channel_volume[0];
f32 RightVol = clip->channel_volume[1];
if(SamplesToMix && control != 0)
{
LeftVol *= control->channel_volume[0];
RightVol *= control->channel_volume[1];
control->generation = Crunky->generation;
control->last_played_sample_index = clip->at_sample_index;
}
// NOTE(casey): Mix samples
for(u32 SampleIndex = 0;
SampleIndex < SamplesToMix;
++SampleIndex)
{
u32 src_index = 2*(clip->at_sample_index + SampleIndex);
f32 Left = LeftVol*(f32)clip->samples[src_index + 0];
f32 Right = RightVol*(f32)clip->samples[src_index + 1];
u32 dst_index = 2*SampleIndex;
MixBuffer[dst_index + 0] += Left;
MixBuffer[dst_index + 1] += Right;
}
}
for(u32 SampleIndex = 0;
SampleIndex < SampleCount;
++SampleIndex)
{
f32 Left = MixBuffer[2*SampleIndex + 0];
f32 Right = MixBuffer[2*SampleIndex + 1];
Dest[2*SampleIndex + 0] = (i16)Left;
Dest[2*SampleIndex + 1] = (i16)Right;
}
}
}
function b32
win32_submit_audio(Audio_System *Crunky, HWAVEOUT WaveOut, WAVEHDR *Header, u32 SampleCount, void *mix_buffer){
win32_submit_audio(HWAVEOUT WaveOut, WAVEHDR *Header, u32 SampleCount, f32 *mix_buffer){
b32 Result = false;
// NOTE(allen): prep buffers
u32 mix_buffer_size = SampleCount*2*sizeof(f32);
memset(mix_buffer, 0, mix_buffer_size);
i16 *Samples = (i16 *)Header->lpData;
win32_mix_audio(Crunky, SampleCount, Samples, mix_buffer);
// NOTE(allen): prep mixer pointers
win32_audio_begin_ticket_mutex();
void *audio_mix_ctx = win32vars.audio_mix_ctx;
Audio_Mix_Sources_Function *audio_mix_sources = win32vars.audio_mix_sources;
Audio_Mix_Destination_Function *audio_mix_destination = win32vars.audio_mix_destination;
win32_audio_end_ticket_mutex();
if (audio_mix_sources == 0){
audio_mix_sources = win32_default_mix_sources;
}
if (audio_mix_destination == 0){
audio_mix_destination = win32_default_mix_destination;
}
// NOTE(allen): mix
audio_mix_sources(audio_mix_ctx, mix_buffer, SampleCount);
audio_mix_destination(Samples, mix_buffer, SampleCount);
// NOTE(allen): send final samples to win32
DWORD Error = waveOutPrepareHeader(WaveOut, Header, sizeof(*Header));
if(Error == MMSYSERR_NOERROR)
{
@ -175,8 +107,6 @@ win32_submit_audio(Audio_System *Crunky, HWAVEOUT WaveOut, WAVEHDR *Header, u32
function DWORD WINAPI
win32_audio_loop(void *Passthrough){
Audio_System *Crunky = (Audio_System *)Passthrough;
//
// NOTE(casey): Set up our audio output buffer
//
@ -206,6 +136,8 @@ win32_audio_loop(void *Passthrough){
Format.nBlockAlign = (Format.nChannels*Format.wBitsPerSample)/8;
Format.nAvgBytesPerSec = Format.nBlockAlign * Format.nSamplesPerSec;
b32 quit = false;
void *MixBuffer = 0;
void *AudioBufferMemory = 0;
if(waveOutOpen(&WaveOut, WAVE_MAPPER, &Format, GetCurrentThreadId(), 0, CALLBACK_THREAD) == MMSYSERR_NOERROR)
@ -227,17 +159,19 @@ win32_audio_loop(void *Passthrough){
At += TotalBufferSize;
win32_submit_audio(Crunky, WaveOut, Header, SamplesPerBuffer, MixBuffer);
win32_submit_audio(WaveOut, Header, SamplesPerBuffer, (f32*)MixBuffer);
}
}
else
{
Crunky->quit = true;
// TODO(allen): audio error
quit = true;
}
}
else
{
Crunky->quit = true;
// TODO(allen): audio error
quit = true;
}
//
@ -245,7 +179,7 @@ win32_audio_loop(void *Passthrough){
//
SetTimer(0, 0, 100, 0);
while(!Crunky->quit)
for (;!quit;)
{
MSG Message = {};
GetMessage(&Message, 0, 0, 0);
@ -259,7 +193,7 @@ win32_audio_loop(void *Passthrough){
waveOutUnprepareHeader(WaveOut, Header, sizeof(*Header));
win32_submit_audio(Crunky, WaveOut, Header, SamplesPerBuffer, MixBuffer);
win32_submit_audio(WaveOut, Header, SamplesPerBuffer, (f32*)MixBuffer);
}
}
@ -277,9 +211,9 @@ win32_audio_loop(void *Passthrough){
}
function DWORD
win32_audio_init(Audio_System *audio_system){
win32_audio_init(void){
DWORD thread_id = 0;
HANDLE handle = CreateThread(0, 0, win32_audio_loop, audio_system, 0, &thread_id);
HANDLE handle = CreateThread(0, 0, win32_audio_loop, 0, 0, &thread_id);
CloseHandle(handle);
return(thread_id);
}