playback layer refactor
This commit is contained in:
parent
634c4c6a02
commit
73f45cd765
@ -248,7 +248,7 @@ void P_AppStartup(String args_str)
|
||||
SimStartupReceipt sim_sr = sim_startup();
|
||||
|
||||
/* Interface systems */
|
||||
PB_StartupReceipt playback_sr = playback_startup(&mixer_sr);
|
||||
PB_StartupReceipt playback_sr = PB_Startup(&mixer_sr);
|
||||
struct user_startup_receipt user_sr = user_startup(&font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &sim_sr, connect_address);
|
||||
|
||||
(UNUSED)user_sr;
|
||||
|
||||
@ -83,6 +83,15 @@ extern "C" {
|
||||
# define LanguageIsC 1
|
||||
#endif
|
||||
|
||||
//- Windows NTDDI version
|
||||
/* FIXME: Remove this */
|
||||
#if 0
|
||||
#if PlatformIsWindows
|
||||
# define NTDDI_WIN11_DT 0x0C0A0000
|
||||
# define NTDDI_VERSION 0x0A000000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Debug
|
||||
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
#if PlatformIsWindows
|
||||
|
||||
////////////////////////////////
|
||||
//~ Windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define UNICODE
|
||||
#include <Windows.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ FiberId
|
||||
|
||||
i16 FiberId(void)
|
||||
{
|
||||
return (i16)(i64)GetFiberData();
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
#if CompilerIsMsvc
|
||||
|
||||
////////////////////////////////
|
||||
//~ Windows headers
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define UNICODE
|
||||
#include <Windows.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ Incbin
|
||||
|
||||
/* Find first resource with `type` and return the data in `udata`. */
|
||||
BOOL CALLBACK IncbinEnumerateResourceNamesFunc(HMODULE module, LPCWSTR type, LPCWSTR wstr_entry_name, LONG_PTR udata)
|
||||
{
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
#if PlatformIsWindows
|
||||
|
||||
////////////////////////////////
|
||||
//~ Memory allocation
|
||||
|
||||
#if PlatformIsWindows
|
||||
//~ Windows headers
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define UNICODE
|
||||
#include <Windows.h>
|
||||
|
||||
////////////////////////////////
|
||||
//~ Memory allocation
|
||||
|
||||
//- Reserve
|
||||
void *ReserveMemory(u64 size)
|
||||
{
|
||||
|
||||
@ -16,6 +16,9 @@ DXC_Result DXC_Compile(Arena *arena, String shader_source, i32 num_args, String
|
||||
# pragma clang diagnostic ignored "-Wlanguage-extension-token"
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Windows headers
|
||||
|
||||
#pragma warning(push, 0)
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define UNICODE
|
||||
@ -28,6 +31,9 @@ DXC_Result DXC_Compile(Arena *arena, String shader_source, i32 num_args, String
|
||||
#pragma comment(lib, "d3dcompiler")
|
||||
#pragma comment(lib, "dxcompiler")
|
||||
|
||||
////////////////////////////////
|
||||
//~ Compile
|
||||
|
||||
/* https://github.com/microsoft/DirectXShaderCompiler/wiki/Using-dxc.exe-and-dxcompiler.dll */
|
||||
DXC_Result DXC_Compile(Arena *arena, String shader_source, i32 num_args, String *args)
|
||||
{
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
////////////////////////////////
|
||||
//~ Windows headers
|
||||
|
||||
#pragma warning(push, 0)
|
||||
# define UNICODE
|
||||
# define COBJMACROS
|
||||
@ -20,6 +23,9 @@
|
||||
# pragma comment(lib, "advapi32")
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Dx12
|
||||
|
||||
#define DX12_ALLOW_TEARING 1
|
||||
#define DX12_WAIT_FRAME_LATENCY 1
|
||||
#define DX12_SWAPCHAIN_FLAGS (((DX12_ALLOW_TEARING != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) | ((DX12_WAIT_FRAME_LATENCY != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
|
||||
|
||||
@ -5,19 +5,4 @@
|
||||
|
||||
#include "mp3_core.h"
|
||||
|
||||
#if PlatformIsWindows
|
||||
#pragma warning(push, 0)
|
||||
# define COBJMACROS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define UNICODE
|
||||
# include <Windows.h>
|
||||
# include <uuids.h>
|
||||
# include <mfapi.h>
|
||||
# include <mfidl.h>
|
||||
# include <mfreadwrite.h>
|
||||
# include <Shlwapi.h>
|
||||
# pragma warning(pop)
|
||||
# include "mp3_mmf.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,7 +1,25 @@
|
||||
////////////////////////////////
|
||||
//~ Windows headers
|
||||
|
||||
#pragma warning(push, 0)
|
||||
# define COBJMACROS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define UNICODE
|
||||
# include <Windows.h>
|
||||
# include <uuids.h>
|
||||
# include <mfapi.h>
|
||||
# include <mfidl.h>
|
||||
# include <mfreadwrite.h>
|
||||
# include <Shlwapi.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#pragma comment(lib, "mfplat")
|
||||
#pragma comment(lib, "mfreadwrite")
|
||||
#pragma comment(lib, "shlwapi")
|
||||
|
||||
////////////////////////////////
|
||||
//~ Decode
|
||||
|
||||
MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeFlag flags)
|
||||
{
|
||||
MP3_Result result = ZI;
|
||||
|
||||
@ -8,24 +8,6 @@
|
||||
#include "platform_log.h"
|
||||
|
||||
#if PlatformIsWindows
|
||||
# pragma warning(push, 0)
|
||||
# define UNICODE
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
/* FIXME: Remove this */
|
||||
# define NTDDI_WIN11_DT 0x0C0A0000
|
||||
# define NTDDI_VERSION 0x0A000000
|
||||
# include <Windows.h>
|
||||
# include <WinSock2.h>
|
||||
# include <TlHelp32.h>
|
||||
# include <WS2tcpip.h>
|
||||
# include <windowsx.h>
|
||||
# include <ShlObj_core.h>
|
||||
# include <fileapi.h>
|
||||
# include <dwmapi.h>
|
||||
# include <bcrypt.h>
|
||||
# include <avrt.h>
|
||||
# include <shellapi.h>
|
||||
# pragma warning(pop)
|
||||
# include "platform_win32.h"
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,3 +1,22 @@
|
||||
////////////////////////////////
|
||||
//~ Win32 headers
|
||||
|
||||
#pragma warning(push, 0)
|
||||
# define UNICODE
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <Windows.h>
|
||||
# include <WinSock2.h>
|
||||
# include <TlHelp32.h>
|
||||
# include <WS2tcpip.h>
|
||||
# include <windowsx.h>
|
||||
# include <ShlObj_core.h>
|
||||
# include <fileapi.h>
|
||||
# include <dwmapi.h>
|
||||
# include <bcrypt.h>
|
||||
# include <avrt.h>
|
||||
# include <shellapi.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
////////////////////////////////
|
||||
//~ Ticket mutex types
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#include "playback.h"
|
||||
|
||||
#if PlatformIsWindows
|
||||
# include "playback_core_win32.c"
|
||||
# include "playback_win32.c"
|
||||
#else
|
||||
# error Playback core not implemented for this platform
|
||||
#endif
|
||||
|
||||
@ -7,4 +7,8 @@
|
||||
|
||||
#include "playback_core.h"
|
||||
|
||||
#if PlatformIsWindows
|
||||
# include "playback_win32.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
#define PB_SampleRate 48000
|
||||
|
||||
Struct(PB_StartupReceipt) { i32 _; };
|
||||
PB_StartupReceipt playback_startup(M_StartupReceipt *mixer_sr);
|
||||
PB_StartupReceipt PB_Startup(M_StartupReceipt *mixer_sr);
|
||||
|
||||
@ -1,77 +1,39 @@
|
||||
/* ========================== *
|
||||
* WASAPI backend for audio playback
|
||||
/* WASAPI backend for audio playback
|
||||
*
|
||||
* Based on mmozeiko's WASAPI example
|
||||
* Based on mmozeiko's WASAPI examples
|
||||
* https://gist.github.com/mmozeiko/5a5b168e61aff4c1eaec0381da62808f#file-win32_wasapi-h
|
||||
* ========================== */
|
||||
*/
|
||||
|
||||
#define COBJMACROS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define UNICODE
|
||||
#include <Windows.h>
|
||||
#include <initguid.h>
|
||||
#include <objbase.h>
|
||||
#include <uuids.h>
|
||||
#include <Audioclient.h>
|
||||
#include <mmdeviceapi.h>
|
||||
PB_WSP_SharedState PB_WSP_shared_state = ZI;
|
||||
|
||||
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e);
|
||||
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6);
|
||||
DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2);
|
||||
DEFINE_GUID(IID_IAudioClient3, 0x7ed4ee07, 0x8e67, 0x4cd4, 0x8c, 0x1a, 0x2b, 0x7a, 0x59, 0x87, 0xad, 0x42);
|
||||
DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2);
|
||||
////////////////////////////////
|
||||
//~ Startup
|
||||
|
||||
#define PLAYBACK_SAMPLE_RATE 48000
|
||||
|
||||
struct wasapi_buffer {
|
||||
u32 frames_count;
|
||||
u8 *frames;
|
||||
};
|
||||
|
||||
Global struct {
|
||||
Atomic32 shutdown;
|
||||
IAudioClient *client;
|
||||
HANDLE event;
|
||||
IAudioRenderClient *playback;
|
||||
WAVEFORMATEX *buffer_format;
|
||||
u32 buffer_frames;
|
||||
P_Counter playback_job_counter;
|
||||
} G = ZI, DebugAlias(G, G_playback_wasapi);
|
||||
|
||||
/* ========================== *
|
||||
* Startup
|
||||
* ========================== */
|
||||
|
||||
internal void wasapi_initialize(void);
|
||||
internal P_ExitFuncDef(playback_shutdown);
|
||||
internal P_JobDef(playback_job, _);
|
||||
|
||||
PB_StartupReceipt playback_startup(M_StartupReceipt *mixer_sr)
|
||||
PB_StartupReceipt PB_Startup(M_StartupReceipt *mixer_sr)
|
||||
{
|
||||
__prof;
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
(UNUSED)mixer_sr;
|
||||
wasapi_initialize();
|
||||
PB_WSP_InitializeWasapi();
|
||||
/* Start playback job */
|
||||
P_Run(1, playback_job, 0, P_Pool_Audio, P_Priority_High, &G.playback_job_counter);
|
||||
P_OnExit(&playback_shutdown);
|
||||
P_Run(1, PB_WSP_PlaybackJob, 0, P_Pool_Audio, P_Priority_High, &g->PB_WSP_PlaybackJob_counter);
|
||||
P_OnExit(&PB_WSP_Shutdown);
|
||||
|
||||
return (PB_StartupReceipt) { 0 };
|
||||
}
|
||||
|
||||
internal P_ExitFuncDef(playback_shutdown)
|
||||
P_ExitFuncDef(PB_WSP_Shutdown)
|
||||
{
|
||||
__prof;
|
||||
Atomic32FetchSet(&G.shutdown, 1);
|
||||
P_WaitOnCounter(&G.playback_job_counter);
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
Atomic32FetchSet(&g->shutdown, 1);
|
||||
P_WaitOnCounter(&g->PB_WSP_PlaybackJob_counter);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Wasapi initialization
|
||||
* ========================== */
|
||||
|
||||
internal void wasapi_initialize(void)
|
||||
void PB_WSP_InitializeWasapi(void)
|
||||
{
|
||||
u64 sample_rate = PLAYBACK_SAMPLE_RATE;
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
u64 sample_rate = PB_SampleRate;
|
||||
u64 channel_count = 2;
|
||||
u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
||||
|
||||
@ -85,7 +47,7 @@ internal void wasapi_initialize(void)
|
||||
IMMDeviceEnumerator_Release(enumerator);
|
||||
|
||||
/* Create audio client for device */
|
||||
IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&G.client);
|
||||
IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client);
|
||||
IMMDevice_Release(device);
|
||||
|
||||
WAVEFORMATEXTENSIBLE format_ex = {
|
||||
@ -107,7 +69,8 @@ internal void wasapi_initialize(void)
|
||||
#if 0
|
||||
b32 client_initialized = 0;
|
||||
IAudioClient3 *client3;
|
||||
if (SUCCEEDED(IAudioClient_QueryInterface(G.client, &IID_IAudioClient3, (LPVOID *)&client3))) {
|
||||
if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3)))
|
||||
{
|
||||
/* From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz)
|
||||
* but it can be 128 samples (2.66 msec @ 48khz) if driver is properly installed
|
||||
* see bullet-point instructions here: https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio#measurement-tools
|
||||
@ -116,7 +79,8 @@ internal void wasapi_initialize(void)
|
||||
IAudioClient3_GetSharedModeEnginePeriod(client3, wfx, &default_period_samples, &fundamental_period_samples, &min_period_samples, &max_period_samples);
|
||||
|
||||
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
|
||||
if (SUCCEEDED(IAudioClient3_InitializeSharedAudioStream(client3, flags, min_period_samples, wfx, 0))) {
|
||||
if (SUCCEEDED(IAudioClient3_InitializeSharedAudioStream(client3, flags, min_period_samples, wfx, 0)))
|
||||
{
|
||||
client_initialized = 1;
|
||||
}
|
||||
|
||||
@ -126,10 +90,11 @@ internal void wasapi_initialize(void)
|
||||
b32 client_initialized = 0;
|
||||
#endif
|
||||
|
||||
if (!client_initialized) {
|
||||
if (!client_initialized)
|
||||
{
|
||||
/* Get duration for shared-mode streams, this will typically be 480 samples (10msec @ 48khz) */
|
||||
REFERENCE_TIME duration;
|
||||
IAudioClient_GetDevicePeriod(G.client, &duration, 0);
|
||||
IAudioClient_GetDevicePeriod(g->client, &duration, 0);
|
||||
|
||||
/* Initialize audio playback
|
||||
*
|
||||
@ -139,66 +104,71 @@ internal void wasapi_initialize(void)
|
||||
* but allows for any input format.
|
||||
*/
|
||||
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
|
||||
IAudioClient_Initialize(G.client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0);
|
||||
IAudioClient_Initialize(g->client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0);
|
||||
}
|
||||
|
||||
IAudioClient_GetMixFormat(G.client, &G.buffer_format);
|
||||
IAudioClient_GetMixFormat(g->client, &g->buffer_format);
|
||||
|
||||
/* Set up event handler to wait on */
|
||||
G.event = CreateEventW(0, 0, 0, 0);
|
||||
IAudioClient_SetEventHandle(G.client, G.event);
|
||||
g->event = CreateEventW(0, 0, 0, 0);
|
||||
IAudioClient_SetEventHandle(g->client, g->event);
|
||||
|
||||
/* Get playback client */
|
||||
IAudioClient_GetService(G.client, &IID_IAudioRenderClient, (LPVOID *)&G.playback);
|
||||
IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback);
|
||||
|
||||
/* Start the playback */
|
||||
IAudioClient_Start(G.client);
|
||||
IAudioClient_Start(g->client);
|
||||
|
||||
/* Get audio buffer size in samples */
|
||||
IAudioClient_GetBufferSize(G.client, &G.buffer_frames);
|
||||
IAudioClient_GetBufferSize(g->client, &g->buffer_frames);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Playback thread update
|
||||
* ========================== */
|
||||
////////////////////////////////
|
||||
//~ Wasapi update
|
||||
|
||||
internal struct wasapi_buffer wasapi_update_begin(void)
|
||||
PB_WSP_Buff PB_WSP_BeginUpdate(void)
|
||||
{
|
||||
__prof;
|
||||
struct wasapi_buffer wspbuf = ZI;
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
PB_WSP_Buff wspbuf = ZI;
|
||||
|
||||
/* Get padding frames */
|
||||
u32 padding_frames;
|
||||
IAudioClient_GetCurrentPadding(G.client, &padding_frames);
|
||||
IAudioClient_GetCurrentPadding(g->client, &padding_frames);
|
||||
|
||||
/* Get output buffer from WASAPI */
|
||||
wspbuf.frames_count = 0;
|
||||
if (padding_frames <= G.buffer_frames) {
|
||||
wspbuf.frames_count = G.buffer_frames - padding_frames;
|
||||
if (padding_frames <= g->buffer_frames)
|
||||
{
|
||||
wspbuf.frames_count = g->buffer_frames - padding_frames;
|
||||
}
|
||||
IAudioRenderClient_GetBuffer(G.playback, wspbuf.frames_count, &wspbuf.frames);
|
||||
IAudioRenderClient_GetBuffer(g->playback, wspbuf.frames_count, &wspbuf.frames);
|
||||
|
||||
return wspbuf;
|
||||
}
|
||||
|
||||
internal void wasapi_update_end(struct wasapi_buffer *wspbuf, M_PcmF32 src)
|
||||
void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, M_PcmF32 src)
|
||||
{
|
||||
__prof;
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
u32 frames_in_source = src.count / 2;
|
||||
u32 frames_in_output = wspbuf->frames_count;
|
||||
|
||||
u32 flags = 0;
|
||||
if (frames_in_source == frames_in_output) {
|
||||
if (frames_in_source == frames_in_output)
|
||||
{
|
||||
/* Copy bytes to output */
|
||||
u32 bytes_per_sample = G.buffer_format->nBlockAlign / G.buffer_format->nChannels;
|
||||
u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels;
|
||||
u32 write_size = frames_in_source * 2 * bytes_per_sample;
|
||||
CopyBytes(wspbuf->frames, src.samples, write_size);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Submit silence if not enough samples */
|
||||
flags = AUDCLNT_BUFFERFLAGS_SILENT;
|
||||
|
||||
/* This shouldn't occur, mixer should be generating samples equivilent
|
||||
* to value returned from `wasapi_update_begin`. */
|
||||
* to value returned from `PB_WSP_BeginUpdate`. */
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
@ -207,33 +177,34 @@ internal void wasapi_update_end(struct wasapi_buffer *wspbuf, M_PcmF32 src)
|
||||
#endif
|
||||
|
||||
/* Submit output buffer to WASAPI */
|
||||
IAudioRenderClient_ReleaseBuffer(G.playback, frames_in_source, flags);
|
||||
IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags);
|
||||
__profframe("Audio");
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Playback thread entry
|
||||
* ========================== */
|
||||
////////////////////////////////
|
||||
//~ Playback job
|
||||
|
||||
internal P_JobDef(playback_job, _)
|
||||
P_JobDef(PB_WSP_PlaybackJob, _)
|
||||
{
|
||||
__prof;
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
(UNUSED)_;
|
||||
|
||||
/* FIXME: If playback fails at any point and mixer stops advancing, we
|
||||
* need to halt mixer to prevent memory leak when sounds are played. */
|
||||
/* TODO: Signal counter that running job wiats on, rather than scheduling job manually */
|
||||
while (!Atomic32Fetch(&G.shutdown)) {
|
||||
while (!Atomic32Fetch(&g->shutdown))
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
__profn("Wasapi wait");
|
||||
WaitForSingleObject(G.event, INFINITE);
|
||||
WaitForSingleObject(g->event, INFINITE);
|
||||
}
|
||||
{
|
||||
__profn("Fill sample buffer");
|
||||
struct wasapi_buffer wspbuf = wasapi_update_begin();
|
||||
PB_WSP_Buff wspbuf = PB_WSP_BeginUpdate();
|
||||
M_PcmF32 pcm = M_MixAllTracks(scratch.arena, wspbuf.frames_count);
|
||||
wasapi_update_end(&wspbuf, pcm);
|
||||
PB_WSP_EndUpdate(&wspbuf, pcm);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
64
src/playback/playback_win32.h
Normal file
64
src/playback/playback_win32.h
Normal file
@ -0,0 +1,64 @@
|
||||
////////////////////////////////
|
||||
//~ Win32 headers
|
||||
|
||||
#pragma warning(push, 0)
|
||||
# define COBJMACROS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define UNICODE
|
||||
# include <Windows.h>
|
||||
# include <initguid.h>
|
||||
# include <objbase.h>
|
||||
# include <uuids.h>
|
||||
# include <Audioclient.h>
|
||||
# include <mmdeviceapi.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e);
|
||||
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6);
|
||||
DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2);
|
||||
DEFINE_GUID(IID_IAudioClient3, 0x7ed4ee07, 0x8e67, 0x4cd4, 0x8c, 0x1a, 0x2b, 0x7a, 0x59, 0x87, 0xad, 0x42);
|
||||
DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Wasapi buffer types
|
||||
|
||||
Struct(PB_WSP_Buff)
|
||||
{
|
||||
u32 frames_count;
|
||||
u8 *frames;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Shared state
|
||||
|
||||
Struct(PB_WSP_SharedState)
|
||||
{
|
||||
Atomic32 shutdown;
|
||||
IAudioClient *client;
|
||||
HANDLE event;
|
||||
IAudioRenderClient *playback;
|
||||
WAVEFORMATEX *buffer_format;
|
||||
u32 buffer_frames;
|
||||
P_Counter PB_WSP_PlaybackJob_counter;
|
||||
};
|
||||
|
||||
extern PB_WSP_SharedState PB_WSP_shared_state;
|
||||
|
||||
////////////////////////////////
|
||||
//~ Wasapi startup
|
||||
|
||||
void PB_WSP_InitializeWasapi(void);
|
||||
P_ExitFuncDef(PB_WSP_Shutdown);
|
||||
P_JobDef(PB_WSP_PlaybackJob, _);
|
||||
P_ExitFuncDef(PB_WSP_Shutdown);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Playback update
|
||||
|
||||
PB_WSP_Buff PB_WSP_BeginUpdate(void);
|
||||
void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, M_PcmF32 src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Playback job
|
||||
|
||||
P_JobDef(PB_WSP_PlaybackJob, _);
|
||||
@ -1,7 +1,10 @@
|
||||
/* Based on Allen Webster's dwrite rasterizer example -
|
||||
* https://github.com/4th-dimention/examps */
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define UNICODE
|
||||
#pragma warning(push, 0)
|
||||
# include <Windows.h>
|
||||
# include <dwrite.h>
|
||||
# include <dwrite_3.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user