Hack in new audio system contributed by casey; win32 only for now
This commit is contained in:
parent
45ab2afe61
commit
a9a1931e34
|
@ -303,6 +303,12 @@ define_api(Arena *arena){
|
||||||
api_param(arena, call, "Key_Mode", "mode");
|
api_param(arena, call, "Key_Mode", "mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
API_Call *call = api_call(arena, api, "play_clip", "void");
|
||||||
|
api_param(arena, call, "Audio_Clip", "clip");
|
||||||
|
api_param(arena, call, "Audio_Control*", "control");
|
||||||
|
}
|
||||||
|
|
||||||
return(api);
|
return(api);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Load Clip
|
||||||
|
|
||||||
|
#if !defined(FCODER_SKIP_WAV)
|
||||||
|
#define FCODER_SKIP_WAV
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct wave_fmt_data
|
||||||
|
{
|
||||||
|
u16 wFormatTag;
|
||||||
|
u16 wChannels;
|
||||||
|
u32 dwSamplesPerSec;
|
||||||
|
u32 dwAvgBytesPerSec;
|
||||||
|
u16 wBlockAlign;
|
||||||
|
u16 wBitsPerSample;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct riff_header
|
||||||
|
{
|
||||||
|
u32 ID;
|
||||||
|
u32 DataSize;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
function Audio_Clip
|
||||||
|
audio_clip_from_wav_data(String_Const_u8 data){
|
||||||
|
Audio_Clip Result = {};
|
||||||
|
|
||||||
|
if (data.size >= 4 && *(u32 *)data.str == *(u32 *)"RIFF"){
|
||||||
|
// NOTE(casey): This ROM is in WAV format
|
||||||
|
|
||||||
|
riff_header *RootHeader = (riff_header *)data.str;
|
||||||
|
|
||||||
|
wave_fmt_data *Format = 0;
|
||||||
|
u32 SampleDataSize = 0;
|
||||||
|
i16 *Samples = 0;
|
||||||
|
|
||||||
|
u32 At = sizeof(riff_header);
|
||||||
|
u32 LastAt = At + ((RootHeader->DataSize + 1) & ~1);
|
||||||
|
if ((*(u32 *)(data.str + At) == *(u32 *)"WAVE") &&
|
||||||
|
(LastAt <= data.size)){
|
||||||
|
At += sizeof(u32);
|
||||||
|
while (At < LastAt){
|
||||||
|
riff_header *Header = (riff_header *)(data.str + At);
|
||||||
|
u32 DataAt = At + sizeof(riff_header);
|
||||||
|
u32 EndAt = DataAt + ((Header->DataSize + 1) & ~1);
|
||||||
|
if(EndAt <= data.size)
|
||||||
|
{
|
||||||
|
void *Data = (data.str + DataAt);
|
||||||
|
if(Header->ID == *(u32 *)"fmt ")
|
||||||
|
{
|
||||||
|
Format = (wave_fmt_data *)Data;
|
||||||
|
}
|
||||||
|
else if(Header->ID == *(u32 *)"data")
|
||||||
|
{
|
||||||
|
SampleDataSize = Header->DataSize;
|
||||||
|
Samples = (i16 *)Data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
At = EndAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Format &&
|
||||||
|
Samples &&
|
||||||
|
(Format->wFormatTag == 1) &&
|
||||||
|
(Format->wChannels == 2) &&
|
||||||
|
(Format->wBitsPerSample == 16) &&
|
||||||
|
(Format->dwSamplesPerSec == 48000)){
|
||||||
|
Result.sample_count = SampleDataSize / (Format->wChannels*Format->wBitsPerSample/8);
|
||||||
|
Result.samples = (i16 *)Samples;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// TODO(casey): This is where you would output an error - to 4coder somehow?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// TODO(casey): This is where you would output an error - to 4coder somehow?
|
||||||
|
}
|
||||||
|
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
function Audio_Clip
|
||||||
|
audio_clip_from_wav_file_name(char *file_name){
|
||||||
|
String_Const_u8 data = {};
|
||||||
|
FILE *file = fopen(file_name, "rb");
|
||||||
|
if (file != 0){
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
data.size = ftell(file);
|
||||||
|
data.str = (u8*)malloc(data.size);
|
||||||
|
if (data.str != 0 && data.size > 0){
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
fread(data.str, data.size, 1, file);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Audio_Clip result = audio_clip_from_wav_data(data);
|
||||||
|
return(result);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
/* date = November 23rd 2020 1:18 pm */
|
||||||
|
|
||||||
|
#ifndef FCODER_AUDIO_H
|
||||||
|
#define FCODER_AUDIO_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Load Clip
|
||||||
|
|
||||||
|
function Audio_Clip audio_clip_from_wav_data(String_Const_u8 data);
|
||||||
|
|
||||||
|
#endif //4CODER_AUDIO_H
|
|
@ -18,6 +18,15 @@ CUSTOM_DOC("Default command for responding to a startup event")
|
||||||
load_project(app);
|
load_project(app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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.left_volume_knob = AUDIO_PRODUCER_KNOB_ONE;
|
||||||
|
test_control.right_volume_knob = AUDIO_PRODUCER_KNOB_ONE;
|
||||||
|
system_play_clip(test_clip, &test_control);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CUSTOM_COMMAND_SIG(default_try_exit)
|
CUSTOM_COMMAND_SIG(default_try_exit)
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "4coder_variables.h"
|
#include "4coder_variables.h"
|
||||||
|
#include "4coder_audio.h"
|
||||||
#include "4coder_profile.h"
|
#include "4coder_profile.h"
|
||||||
#include "4coder_async_tasks.h"
|
#include "4coder_async_tasks.h"
|
||||||
#include "4coder_token.h"
|
#include "4coder_token.h"
|
||||||
|
@ -129,6 +130,7 @@
|
||||||
#include "4coder_doc_commands.cpp"
|
#include "4coder_doc_commands.cpp"
|
||||||
#include "4coder_docs.cpp"
|
#include "4coder_docs.cpp"
|
||||||
#include "4coder_variables.cpp"
|
#include "4coder_variables.cpp"
|
||||||
|
#include "4coder_audio.cpp"
|
||||||
|
|
||||||
#include "4coder_examples.cpp"
|
#include "4coder_examples.cpp"
|
||||||
|
|
||||||
|
|
|
@ -787,4 +787,39 @@ struct Process_State{
|
||||||
i64 return_code;
|
i64 return_code;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
|
||||||
|
api(custom)
|
||||||
|
struct Audio_Control{
|
||||||
|
#define AUDIO_PRODUCER_KNOB_ONE 256
|
||||||
|
volatile u32 left_volume_knob;
|
||||||
|
volatile u32 right_volume_knob;
|
||||||
|
volatile u32 generation;
|
||||||
|
volatile u32 last_played_sample_index;;
|
||||||
|
};
|
||||||
|
|
||||||
|
api(custom)
|
||||||
|
struct Audio_Clip{
|
||||||
|
i16 *samples;
|
||||||
|
Audio_Control *control;
|
||||||
|
|
||||||
|
u32 sample_count;
|
||||||
|
u32 at_sample_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
api(custom)
|
||||||
|
struct Audio_System{
|
||||||
|
volatile u32 quit;
|
||||||
|
volatile u32 ticket;
|
||||||
|
volatile u32 serving;
|
||||||
|
volatile u32 generation;
|
||||||
|
|
||||||
|
u32 next_playing_clip_index;
|
||||||
|
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];
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -307,8 +307,8 @@ static Command_Metadata fcoder_metacmd_table[248] = {
|
||||||
{ 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(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_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_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, 23 },
|
{ 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, 67 },
|
{ 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(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_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_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 },
|
{ 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 },
|
||||||
|
|
|
@ -54,6 +54,7 @@ vtable->set_fullscreen = system_set_fullscreen;
|
||||||
vtable->is_fullscreen = system_is_fullscreen;
|
vtable->is_fullscreen = system_is_fullscreen;
|
||||||
vtable->get_keyboard_modifiers = system_get_keyboard_modifiers;
|
vtable->get_keyboard_modifiers = system_get_keyboard_modifiers;
|
||||||
vtable->set_key_mode = system_set_key_mode;
|
vtable->set_key_mode = system_set_key_mode;
|
||||||
|
vtable->play_clip = system_play_clip;
|
||||||
}
|
}
|
||||||
#if defined(DYNAMIC_LINK_API)
|
#if defined(DYNAMIC_LINK_API)
|
||||||
function void
|
function void
|
||||||
|
@ -112,6 +113,7 @@ system_set_fullscreen = vtable->set_fullscreen;
|
||||||
system_is_fullscreen = vtable->is_fullscreen;
|
system_is_fullscreen = vtable->is_fullscreen;
|
||||||
system_get_keyboard_modifiers = vtable->get_keyboard_modifiers;
|
system_get_keyboard_modifiers = vtable->get_keyboard_modifiers;
|
||||||
system_set_key_mode = vtable->set_key_mode;
|
system_set_key_mode = vtable->set_key_mode;
|
||||||
|
system_play_clip = vtable->play_clip;
|
||||||
}
|
}
|
||||||
#undef DYNAMIC_LINK_API
|
#undef DYNAMIC_LINK_API
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
#define system_is_fullscreen_sig() b32 system_is_fullscreen(void)
|
#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_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_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)
|
||||||
typedef String_Const_u8 system_get_path_type(Arena* arena, System_Path_Code path_code);
|
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 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);
|
typedef File_List system_get_file_list_type(Arena* arena, String_Const_u8 directory);
|
||||||
|
@ -106,6 +107,7 @@ typedef b32 system_set_fullscreen_type(b32 full_screen);
|
||||||
typedef b32 system_is_fullscreen_type(void);
|
typedef b32 system_is_fullscreen_type(void);
|
||||||
typedef Input_Modifier_Set system_get_keyboard_modifiers_type(Arena* arena);
|
typedef Input_Modifier_Set system_get_keyboard_modifiers_type(Arena* arena);
|
||||||
typedef void system_set_key_mode_type(Key_Mode mode);
|
typedef void system_set_key_mode_type(Key_Mode mode);
|
||||||
|
typedef void system_play_clip_type(Audio_Clip clip, Audio_Control* control);
|
||||||
struct API_VTable_system{
|
struct API_VTable_system{
|
||||||
system_get_path_type *get_path;
|
system_get_path_type *get_path;
|
||||||
system_get_canonical_type *get_canonical;
|
system_get_canonical_type *get_canonical;
|
||||||
|
@ -161,6 +163,7 @@ system_set_fullscreen_type *set_fullscreen;
|
||||||
system_is_fullscreen_type *is_fullscreen;
|
system_is_fullscreen_type *is_fullscreen;
|
||||||
system_get_keyboard_modifiers_type *get_keyboard_modifiers;
|
system_get_keyboard_modifiers_type *get_keyboard_modifiers;
|
||||||
system_set_key_mode_type *set_key_mode;
|
system_set_key_mode_type *set_key_mode;
|
||||||
|
system_play_clip_type *play_clip;
|
||||||
};
|
};
|
||||||
#if defined(STATIC_LINK_API)
|
#if defined(STATIC_LINK_API)
|
||||||
internal String_Const_u8 system_get_path(Arena* arena, System_Path_Code path_code);
|
internal String_Const_u8 system_get_path(Arena* arena, System_Path_Code path_code);
|
||||||
|
@ -217,6 +220,7 @@ internal b32 system_set_fullscreen(b32 full_screen);
|
||||||
internal b32 system_is_fullscreen(void);
|
internal b32 system_is_fullscreen(void);
|
||||||
internal Input_Modifier_Set system_get_keyboard_modifiers(Arena* arena);
|
internal Input_Modifier_Set system_get_keyboard_modifiers(Arena* arena);
|
||||||
internal void system_set_key_mode(Key_Mode mode);
|
internal void system_set_key_mode(Key_Mode mode);
|
||||||
|
internal void system_play_clip(Audio_Clip clip, Audio_Control* control);
|
||||||
#undef STATIC_LINK_API
|
#undef STATIC_LINK_API
|
||||||
#elif defined(DYNAMIC_LINK_API)
|
#elif defined(DYNAMIC_LINK_API)
|
||||||
global system_get_path_type *system_get_path = 0;
|
global system_get_path_type *system_get_path = 0;
|
||||||
|
@ -273,5 +277,6 @@ global system_set_fullscreen_type *system_set_fullscreen = 0;
|
||||||
global system_is_fullscreen_type *system_is_fullscreen = 0;
|
global system_is_fullscreen_type *system_is_fullscreen = 0;
|
||||||
global system_get_keyboard_modifiers_type *system_get_keyboard_modifiers = 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_set_key_mode_type *system_set_key_mode = 0;
|
||||||
|
global system_play_clip_type *system_play_clip = 0;
|
||||||
#undef DYNAMIC_LINK_API
|
#undef DYNAMIC_LINK_API
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -245,5 +245,10 @@ api_param(arena, call, "Arena*", "arena");
|
||||||
API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("set_key_mode"), string_u8_litexpr("void"), string_u8_litexpr(""));
|
API_Call *call = api_call_with_location(arena, result, string_u8_litexpr("set_key_mode"), string_u8_litexpr("void"), string_u8_litexpr(""));
|
||||||
api_param(arena, call, "Key_Mode", "mode");
|
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");
|
||||||
|
}
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,3 +52,4 @@ api(system) function b32 set_fullscreen(b32 full_screen);
|
||||||
api(system) function b32 is_fullscreen(void);
|
api(system) function b32 is_fullscreen(void);
|
||||||
api(system) function Input_Modifier_Set get_keyboard_modifiers(Arena* arena);
|
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 set_key_mode(Key_Mode mode);
|
||||||
|
api(system) function void play_clip(Audio_Clip clip, Audio_Control* control);
|
||||||
|
|
|
@ -179,6 +179,9 @@ struct Win32_Vars{
|
||||||
HWND window_handle;
|
HWND window_handle;
|
||||||
f32 screen_scale_factor;
|
f32 screen_scale_factor;
|
||||||
|
|
||||||
|
Audio_System audio_system;
|
||||||
|
DWORD audio_thread_id;
|
||||||
|
|
||||||
f64 count_per_usecond;
|
f64 count_per_usecond;
|
||||||
b32 first;
|
b32 first;
|
||||||
i32 running_cli;
|
i32 running_cli;
|
||||||
|
@ -259,6 +262,7 @@ handle_type_ptr(void *ptr){
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
#include "win32_4ed_functions.cpp"
|
#include "win32_4ed_functions.cpp"
|
||||||
|
#include "win32_audio.cpp"
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
|
@ -355,9 +359,16 @@ system_set_key_mode_sig(){
|
||||||
win32vars.key_mode = mode;
|
win32vars.key_mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
////////////////////////////////
|
||||||
// Clipboard
|
// NOTE(allen): Audio
|
||||||
//
|
|
||||||
|
internal
|
||||||
|
system_play_clip_sig(){
|
||||||
|
win32_play_clip(clip, control);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Clipboard
|
||||||
|
|
||||||
internal String_Const_u8
|
internal String_Const_u8
|
||||||
win32_read_clipboard_contents(Thread_Context *tctx, Arena *arena){
|
win32_read_clipboard_contents(Thread_Context *tctx, Arena *arena){
|
||||||
|
@ -1783,10 +1794,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// NOTE(allen): Window Init
|
||||||
// Window and GL Initialization
|
|
||||||
//
|
|
||||||
|
|
||||||
RECT window_rect = {};
|
RECT window_rect = {};
|
||||||
if (plat_settings.set_window_size){
|
if (plat_settings.set_window_size){
|
||||||
window_rect.right = plat_settings.window_w;
|
window_rect.right = plat_settings.window_w;
|
||||||
|
@ -1811,10 +1819,10 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdS
|
||||||
GetClientRect(win32vars.window_handle, &window_rect);
|
GetClientRect(win32vars.window_handle, &window_rect);
|
||||||
win32_resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top);
|
win32_resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top);
|
||||||
|
|
||||||
//
|
// NOTE(allen): Audio Init
|
||||||
// Misc System Initializations
|
win32vars.audio_thread_id = win32_audio_init(&win32vars.audio_system);
|
||||||
//
|
|
||||||
|
|
||||||
|
// NOTE(allen): Misc Init
|
||||||
if (!AddClipboardFormatListener(win32vars.window_handle)){
|
if (!AddClipboardFormatListener(win32vars.window_handle)){
|
||||||
Scratch_Block scratch(win32vars.tctx);
|
Scratch_Block scratch(win32vars.tctx);
|
||||||
win32_output_error_string(scratch, ErrorString_UseLog);
|
win32_output_error_string(scratch, ErrorString_UseLog);
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Win32 Audio Functions
|
||||||
|
|
||||||
|
function u32
|
||||||
|
AtomicAddU32AndReturnOriginal(u32 volatile *Value, u32 Addend)
|
||||||
|
{
|
||||||
|
// NOTE(casey): Returns the original value _prior_ to adding
|
||||||
|
u32 Result = _InterlockedExchangeAdd(Value, Addend);
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
win32_begin_ticket_mutex(Audio_System *Crunky)
|
||||||
|
{
|
||||||
|
u32 Ticket = AtomicAddU32AndReturnOriginal(&Crunky->ticket, 1);
|
||||||
|
while(Ticket != Crunky->serving) {_mm_pause();}
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
win32_end_ticket_mutex(Audio_System *Crunky)
|
||||||
|
{
|
||||||
|
AtomicAddU32AndReturnOriginal(&Crunky->serving, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
win32_play_clip(Audio_Clip clip, Audio_Control *control){
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
function void
|
||||||
|
win32_mix_audio(Audio_System *Crunky, u32 SampleCount, i16 *Dest){
|
||||||
|
// NOTE(casey): Move pending sounds into the playing list
|
||||||
|
win32_begin_ticket_mutex(Crunky);
|
||||||
|
++Crunky->generation;
|
||||||
|
for(u32 PendIndex = 0;
|
||||||
|
PendIndex < Crunky->pending_clip_count;
|
||||||
|
++PendIndex)
|
||||||
|
{
|
||||||
|
u32 DestIndex = Crunky->next_playing_clip_index++ % ArrayCount(Crunky->playing_clips);
|
||||||
|
Crunky->playing_clips[DestIndex] = Crunky->pending_clips[PendIndex];
|
||||||
|
}
|
||||||
|
Crunky->pending_clip_count = 0;
|
||||||
|
win32_end_ticket_mutex(Crunky);
|
||||||
|
|
||||||
|
memset(Dest, 0, SampleCount*4);
|
||||||
|
for(u32 SoundIndex = 0;
|
||||||
|
SoundIndex < ArrayCount(Crunky->playing_clips);
|
||||||
|
++SoundIndex)
|
||||||
|
{
|
||||||
|
Audio_Clip Sound = Crunky->playing_clips[SoundIndex];
|
||||||
|
u32 SamplesToMix = Min((Sound.sample_count - Sound.at_sample_index), SampleCount);
|
||||||
|
Crunky->playing_clips[SoundIndex].at_sample_index += SamplesToMix;
|
||||||
|
|
||||||
|
i32 LeftVol = AUDIO_PRODUCER_KNOB_ONE;
|
||||||
|
i32 RightVol = AUDIO_PRODUCER_KNOB_ONE;
|
||||||
|
if(SamplesToMix && Sound.control)
|
||||||
|
{
|
||||||
|
LeftVol = Sound.control->left_volume_knob;
|
||||||
|
RightVol = Sound.control->right_volume_knob;
|
||||||
|
Sound.control->generation = Crunky->generation;
|
||||||
|
Sound.control->last_played_sample_index = Crunky->playing_clips[SoundIndex].at_sample_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for(u32 SampleIndex = 0;
|
||||||
|
SampleIndex < SamplesToMix;
|
||||||
|
++SampleIndex)
|
||||||
|
{
|
||||||
|
u32 src_base_indx = 2*(Sound.at_sample_index + SampleIndex);
|
||||||
|
u32 dst_base_indx = 2*SampleIndex;
|
||||||
|
Dest[dst_base_indx + 0] += (i16)(LeftVol*(i32)Sound.samples[src_base_indx + 0]/AUDIO_PRODUCER_KNOB_ONE);
|
||||||
|
Dest[dst_base_indx + 1] += (i16)(RightVol*(i32)Sound.samples[src_base_indx + 1]/AUDIO_PRODUCER_KNOB_ONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function b32
|
||||||
|
win32_submit_audio(Audio_System *Crunky, HWAVEOUT WaveOut, WAVEHDR *Header){
|
||||||
|
b32 Result = false;
|
||||||
|
|
||||||
|
u32 SampleCount = Header->dwBufferLength/4;
|
||||||
|
i16 *Samples = (i16 *)Header->lpData;
|
||||||
|
win32_mix_audio(Crunky, SampleCount, Samples);
|
||||||
|
|
||||||
|
DWORD Error = waveOutPrepareHeader(WaveOut, Header, sizeof(*Header));
|
||||||
|
if(Error == MMSYSERR_NOERROR)
|
||||||
|
{
|
||||||
|
Error = waveOutWrite(WaveOut, Header, sizeof(*Header));
|
||||||
|
if(Error == MMSYSERR_NOERROR)
|
||||||
|
{
|
||||||
|
// NOTE(casey): Success
|
||||||
|
Result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DWORD WINAPI
|
||||||
|
win32_audio_loop(void *Passthrough){
|
||||||
|
Audio_System *Crunky = (Audio_System *)Passthrough;
|
||||||
|
|
||||||
|
//
|
||||||
|
// NOTE(casey): Set up our audio output buffer
|
||||||
|
//
|
||||||
|
u32 SamplesPerSecond = 48000;
|
||||||
|
u32 SamplesPerBuffer = 16*SamplesPerSecond/1000;
|
||||||
|
u32 ChannelCount = 2;
|
||||||
|
u32 BytesPerChannelValue = 2;
|
||||||
|
u32 BytesPerSample = ChannelCount*BytesPerChannelValue;
|
||||||
|
|
||||||
|
u32 BufferCount = 3;
|
||||||
|
u32 BufferSize = SamplesPerBuffer*BytesPerSample;
|
||||||
|
u32 HeaderSize = sizeof(WAVEHDR);
|
||||||
|
u32 TotalBufferSize = (BufferSize+HeaderSize);
|
||||||
|
u32 TotalAudioMemorySize = BufferCount*TotalBufferSize;
|
||||||
|
|
||||||
|
//
|
||||||
|
// NOTE(casey): Initialize audio out
|
||||||
|
//
|
||||||
|
HWAVEOUT WaveOut = {};
|
||||||
|
|
||||||
|
WAVEFORMATEX Format = {};
|
||||||
|
Format.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
Format.nChannels = (WORD)ChannelCount;
|
||||||
|
Format.wBitsPerSample = (WORD)(8*BytesPerChannelValue);
|
||||||
|
Format.nSamplesPerSec = SamplesPerSecond;
|
||||||
|
Format.nBlockAlign = (Format.nChannels*Format.wBitsPerSample)/8;
|
||||||
|
Format.nAvgBytesPerSec = Format.nBlockAlign * Format.nSamplesPerSec;
|
||||||
|
|
||||||
|
if(waveOutOpen(&WaveOut, WAVE_MAPPER, &Format, GetCurrentThreadId(), 0, CALLBACK_THREAD) == MMSYSERR_NOERROR)
|
||||||
|
{
|
||||||
|
void *AudioBufferMemory = VirtualAlloc(0, TotalAudioMemorySize, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if(AudioBufferMemory)
|
||||||
|
{
|
||||||
|
u8 *At = (u8 *)AudioBufferMemory;
|
||||||
|
for(u32 BufferIndex = 0;
|
||||||
|
BufferIndex < BufferCount;
|
||||||
|
++BufferIndex)
|
||||||
|
{
|
||||||
|
WAVEHDR *Header = (WAVEHDR *)At;
|
||||||
|
At += sizeof(WAVEHDR);
|
||||||
|
Header->lpData = (char *)At;
|
||||||
|
Header->dwBufferLength = TotalBufferSize;
|
||||||
|
|
||||||
|
At += TotalBufferSize;
|
||||||
|
|
||||||
|
win32_submit_audio(Crunky, WaveOut, Header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Crunky->quit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Crunky->quit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// NOTE(casey): Serve audio forever (until we are told to stop)
|
||||||
|
//
|
||||||
|
// SetTimer(0, 0, 100, 0);
|
||||||
|
while(!Crunky->quit)
|
||||||
|
{
|
||||||
|
MSG Message = {};
|
||||||
|
GetMessage(&Message, 0, 0, 0);
|
||||||
|
if(Message.message == MM_WOM_DONE)
|
||||||
|
{
|
||||||
|
WAVEHDR *Header = (WAVEHDR *)Message.lParam;
|
||||||
|
if(Header->dwFlags & WHDR_DONE)
|
||||||
|
{
|
||||||
|
Header->dwFlags &= ~WHDR_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
waveOutUnprepareHeader(WaveOut, Header, sizeof(*Header));
|
||||||
|
|
||||||
|
win32_submit_audio(Crunky, WaveOut, Header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DWORD
|
||||||
|
win32_audio_init(Audio_System *audio_system){
|
||||||
|
DWORD thread_id = 0;
|
||||||
|
HANDLE handle = CreateThread(0, 0, win32_audio_loop, audio_system, 0, &thread_id);
|
||||||
|
CloseHandle(handle);
|
||||||
|
return(thread_id);
|
||||||
|
}
|
Loading…
Reference in New Issue