git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

SDL/audio/xaudio2.c

      1 #define COBJMACROS
      2 #include "audio.h"
      3 #include <Windows.h>
      4 #ifdef REDIST_XAUDIO
      5 #include <xaudio2redist.h>
      6 #else
      7 #include <xaudio2.h>
      8 #endif
      9 #include <initguid.h>
     10 #include <Mmdeviceapi.h>
     11 
     12 // This is a hack, but Windows itself is a hack so I don't care
     13 #define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
     14 DEFINE_GUID(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
     15 
     16 #define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
     17 DEFINE_GUID(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
     18 
     19 DEFINE_CLSID(MMDeviceEnumerator, bcde0395, e52f, 467c, 8e, 3d, c4, 57, 92, 91, 69, 2e);
     20 DEFINE_IID(IMMDeviceEnumerator,  a95664d2, 9614, 4f35, a7, 46, de, 8d, b6, 36, 17, e6);
     21 
     22 
     23 static unsigned audio_frequency = 48000;
     24 static IXAudio2 *xaudio2 = NULL;
     25 static IXAudio2MasteringVoice *master_voice = NULL;
     26 static IXAudio2SourceVoice *source_voice = NULL;
     27 static bool playing = false;
     28 static GB_sample_t sample_pool[0x2000];
     29 static unsigned pos = 0;
     30 
     31 #define BATCH_SIZE 256
     32 
     33 static WAVEFORMATEX wave_format = {
     34     .wFormatTag = WAVE_FORMAT_PCM,
     35     .nChannels = 2,
     36     .nBlockAlign = 4,
     37     .wBitsPerSample = 16,
     38     .cbSize = 0
     39 };
     40 
     41 static bool _audio_is_playing(void)
     42 {
     43     return playing;
     44 }
     45 
     46 static void _audio_clear_queue(void)
     47 {
     48     pos = 0;
     49     IXAudio2SourceVoice_FlushSourceBuffers(source_voice);
     50 }
     51 
     52 static void _audio_set_paused(bool paused)
     53 {
     54     if (paused) {
     55         playing = false;
     56         IXAudio2SourceVoice_Stop(source_voice, 0, XAUDIO2_COMMIT_NOW);
     57         _audio_clear_queue();
     58     }
     59     else {
     60         playing = true;
     61         IXAudio2SourceVoice_Start(source_voice, 0, XAUDIO2_COMMIT_NOW);
     62     }
     63     
     64 }
     65 
     66 
     67 #define _DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) static const PROPERTYKEY name = { { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }, pid }
     68 _DEFINE_PROPERTYKEY(_PKEY_AudioEngine_DeviceFormat, 0xf19f064d, 0x82c, 0x4e27, 0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c, 0);
     69 
     70 
     71 static void update_frequency(void)
     72 {
     73     HRESULT hr;
     74     IMMDevice  *device = NULL;
     75     IMMDeviceEnumerator *enumerator = NULL;
     76     IPropertyStore *store = NULL;
     77     PWAVEFORMATEX deviceFormatProperties;
     78     PROPVARIANT prop;
     79     
     80     hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator);
     81     if (FAILED(hr)) return;
     82     
     83     // get default audio endpoint
     84     
     85     hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eMultimedia, &device);
     86     if (FAILED(hr)) return;
     87     
     88     hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &store);
     89     if (FAILED(hr)) return;
     90     
     91     hr = IPropertyStore_GetValue(store, &_PKEY_AudioEngine_DeviceFormat, &prop);
     92     if (FAILED(hr)) return;
     93     
     94     deviceFormatProperties = (PWAVEFORMATEX)prop.blob.pBlobData;
     95     audio_frequency = deviceFormatProperties->nSamplesPerSec;
     96     if (audio_frequency < 8000 || audio_frequency > 192000) {
     97         // Bogus value, revert to 48KHz
     98         audio_frequency = 48000;
     99     }
    100 }
    101 
    102 static unsigned _audio_get_frequency(void)
    103 {
    104     return audio_frequency;
    105 }
    106 
    107 static size_t _audio_get_queue_length(void)
    108 {
    109     static XAUDIO2_VOICE_STATE state;
    110     IXAudio2SourceVoice_GetState(source_voice, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
    111     
    112     return state.BuffersQueued * BATCH_SIZE + (pos & (BATCH_SIZE - 1));
    113 }
    114 
    115 static void _audio_queue_sample(GB_sample_t *sample)
    116 {
    117     if (!playing) return;
    118         
    119     static XAUDIO2_BUFFER buffer = {.AudioBytes = sizeof(*sample) * BATCH_SIZE, };
    120     sample_pool[pos] = *sample;
    121     buffer.pAudioData = (void *)&sample_pool[pos & ~(BATCH_SIZE - 1)];
    122     pos++;
    123     pos &= 0x1fff;
    124     if ((pos & (BATCH_SIZE - 1)) == 0) {
    125         IXAudio2SourceVoice_SubmitSourceBuffer(source_voice, &buffer, NULL);
    126     }
    127 }
    128 
    129 static bool _audio_init(void)
    130 {
    131     HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    132     if (FAILED(hr)) {
    133         fprintf(stderr, "CoInitializeEx failed: %lx\n", hr);
    134         return false;
    135     }
    136     
    137     hr = XAudio2Create(&xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR);
    138     if (FAILED(hr)) {
    139         fprintf(stderr, "XAudio2Create failed: %lx\n", hr);
    140         return false;
    141     }
    142     
    143     update_frequency();
    144     
    145     hr = IXAudio2_CreateMasteringVoice(xaudio2, &master_voice,
    146                                        2, // 2 channels
    147                                        audio_frequency,
    148                                        0, // Flags
    149                                        0, // Device index
    150                                        NULL, // Effect chain
    151                                        AudioCategory_GameMedia // Category
    152                                       );
    153     if (FAILED(hr)) {
    154         fprintf(stderr, "CreateMasteringVoice failed: %lx\n", hr);
    155         return false;
    156     }
    157     
    158     wave_format.nSamplesPerSec = audio_frequency;
    159     wave_format.nAvgBytesPerSec = audio_frequency * 4;
    160     hr = IXAudio2_CreateSourceVoice(xaudio2, &source_voice, &wave_format, 0, XAUDIO2_DEFAULT_FREQ_RATIO, NULL, NULL, NULL);
    161     
    162     if (FAILED(hr)) {
    163         fprintf(stderr, "CreateSourceVoice failed: %lx\n", hr);
    164         return false;
    165     }
    166     
    167     return true;
    168 }
    169 
    170 static void _audio_deinit(void)
    171 {
    172     _audio_set_paused(true);
    173 }
    174 
    175 GB_AUDIO_DRIVER(XAudio2);

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.