diff --git a/.ci/build.sh b/.ci/build.sh index a791521f5..493f42789 100644 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -298,6 +298,9 @@ EOF # Link against the system libslirp instead of compiling ours. cmake_flags_extra="$cmake_flags_extra -D SLIRP_EXTERNAL=ON" + + # Use OpenAL for Linux builds before FAudio builds are set up. + cmake_flags_extra="$cmake_flags_extra -D OPENAL=ON" fi # Clean workspace. diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 4bc84e91c..2e4753927 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -252,7 +252,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install dependencies - run: sudo apt update && sudo apt install gcc-11 g++-11 libfreetype-dev libsdl2-dev libpng-dev libopenal-dev libc6-dev librtmidi-dev qtbase5-dev qttools5-dev + run: sudo apt update && sudo apt install gcc-11 g++-11 libfreetype-dev libsdl2-dev libpng-dev libopenal-dev libc6-dev librtmidi-dev qtbase5-dev qttools5-dev libfaudio-dev - name: Configure CMake run: >- cmake -S . -B build @@ -316,7 +316,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install dependencies - run: brew install freetype sdl2 libpng openal-soft rtmidi qt@5 + run: brew install freetype sdl2 libpng openal-soft rtmidi qt@5 faudio - name: Configure CMake run: >- cmake -S . -B build diff --git a/CMakeLists.txt b/CMakeLists.txt index ff59cbc6b..0aa4c7b56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,8 +114,7 @@ set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) # ------ ----------- ---- option(RELEASE "Release build" OFF) option(DYNAREC "Dynamic recompiler" ON) -option(OPENAL "OpenAL" ON) -option(FAUDIO "FAudio" OFF) +option(OPENAL "OpenAL" OFF) option(FLUIDSYNTH "FluidSynth" ON) option(MUNT "MUNT" ON) option(DINPUT "DirectInput" OFF) diff --git a/src/86box.c b/src/86box.c index 9647a8a6e..2e49184ef 100644 --- a/src/86box.c +++ b/src/86box.c @@ -941,9 +941,7 @@ pc_reset_hard_close(void) scsi_disk_close(); -#ifdef USE_OPENAL closeal(); -#endif video_reset_close(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ba0cffc7d..674346065 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,7 +43,7 @@ if(VNC) add_compile_definitions(USE_VNC) add_library(vnc OBJECT vnc.c vnc_keymap.c) target_link_libraries(86Box vnc vncserver) - if (WIN32) + if(WIN32) target_link_libraries(86Box ws2_32) endif() endif() @@ -86,28 +86,6 @@ if(APPLE) target_link_libraries(86Box Freetype::Freetype) endif() -if(FAUDIO) - find_package(FAudio REQUIRED) - target_link_libraries(86Box FAudio::FAudio) -endif() - -if(OPENAL AND NOT FAUDIO) - if(VCPKG_TOOLCHAIN) - find_package(OpenAL CONFIG REQUIRED) - elseif(MINGW) - find_package(OpenAL MODULE REQUIRED) - else() - find_package(OpenAL REQUIRED) - endif() - - if(TARGET OpenAL::OpenAL) - target_link_libraries(86Box OpenAL::OpenAL) - else() - include_directories(${OPENAL_INCLUDE_DIR}) - target_link_libraries(86Box ${OPENAL_LIBRARY}) - endif() -endif() - find_package(SDL2 REQUIRED) include_directories(${SDL2_INCLUDE_DIRS}) if(STATIC_BUILD AND TARGET SDL2::SDL2-static) diff --git a/src/include/FAudio_compat.h b/src/include/FAudio_compat.h new file mode 100644 index 000000000..eb901a184 --- /dev/null +++ b/src/include/FAudio_compat.h @@ -0,0 +1,106 @@ +/* map xaudio2 API to faudio API */ +typedef uint32_t HRESULT; +typedef uint32_t UINT32; +typedef uint32_t DWORD; +typedef uint8_t BOOL; + +#define WINAPI FAUDIOCALL + +#define TRUE 1 +#define FALSE 0 + +#define S_OK 0 +#define XAUDIO2_E_INVALID_CALL FAUDIO_E_INVALID_CALL + +#define XAUDIO2_DEFAULT_PROCESSOR FAUDIO_DEFAULT_PROCESSOR +#define XAUDIO2_COMMIT_NOW FAUDIO_COMMIT_NOW +#define XAUDIO2_END_OF_STREAM FAUDIO_END_OF_STREAM + +#define WAVE_FORMAT_PCM FAUDIO_FORMAT_PCM +#define WAVE_FORMAT_IEEE_FLOAT FAUDIO_FORMAT_IEEE_FLOAT + +#define AudioCategory_GameEffects FAudioStreamCategory_GameEffects + +#define GlobalDefaultDevice FAudioGlobalDefaultDevice +#define NotDefaultDevice FAudioNotDefaultDevice + +#define XAudio2Create FAudioCreate + +typedef FAudioBuffer XAUDIO2_BUFFER; +typedef FAudioDeviceDetails XAUDIO2_DEVICE_DETAILS; +typedef FAudioEffectChain XAUDIO2_EFFECT_CHAIN; +typedef FAudioEffectDescriptor XAUDIO2_EFFECT_DESCRIPTOR; +typedef FAudioVoiceDetails XAUDIO2_VOICE_DETAILS; +typedef FAudioVoiceDetails XAUDIO27_VOICE_DETAILS; +typedef FAudioVoiceState XAUDIO2_VOICE_STATE; +typedef FAudioWaveFormatEx WAVEFORMATEX; +typedef FAudioPerformanceData XAUDIO2_PERFORMANCE_DATA; + +typedef FAudioEngineCallback IXAudio2EngineCallback; +typedef FAudioVoiceCallback IXAudio2VoiceCallback; + +typedef FAPO IXAPO; + +typedef FAudio IXAudio27; +#define IXAudio27_CreateMasteringVoice FAudio_CreateMasteringVoice +#define IXAudio27_CreateSourceVoice FAudio_CreateSourceVoice +#define IXAudio27_CreateSubmixVoice FAudio_CreateSubmixVoice +#define IXAudio27_GetDeviceCount FAudio_GetDeviceCount +#define IXAudio27_GetDeviceDetails FAudio_GetDeviceDetails +#define IXAudio27_GetPerformanceData FAudio_GetPerformanceData +#define IXAudio27_Initialize FAudio_Initialize +#define IXAudio27_RegisterForCallbacks FAudio_RegisterForCallbacks +#define IXAudio27_Release FAudio_Release +#define IXAudio27_StartEngine FAudio_StartEngine +#define IXAudio27_StopEngine FAudio_StopEngine +#define IXAudio27_UnregisterForCallbacks FAudio_UnregisterForCallbacks + +typedef FAudio IXAudio2; +#define IXAudio2_CreateMasteringVoice FAudio_CreateMasteringVoice8 +#define IXAudio2_CreateSourceVoice FAudio_CreateSourceVoice +#define IXAudio2_CreateSubmixVoice FAudio_CreateSubmixVoice +#define IXAudio2_GetPerformanceData FAudio_GetPerformanceData +#define IXAudio2_RegisterForCallbacks FAudio_RegisterForCallbacks +#define IXAudio2_Release FAudio_Release +#define IXAudio2_StartEngine FAudio_StartEngine +#define IXAudio2_StopEngine FAudio_StopEngine +#define IXAudio2_UnregisterForCallbacks FAudio_UnregisterForCallbacks + +typedef FAudioMasteringVoice IXAudio2MasteringVoice; +#define IXAudio2MasteringVoice_DestroyVoice FAudioVoice_DestroyVoice +#define IXAudio2MasteringVoice_GetChannelMask FAudioMasteringVoice_GetChannelMask +#define IXAudio2MasteringVoice_SetEffectChain FAudioVoice_SetEffectChain +#define IXAudio2MasteringVoice_SetVolume FAudioVoice_SetVolume + +typedef FAudioSourceVoice IXAudio27SourceVoice; +#define IXAudio27SourceVoice_DestroyVoice FAudioVoice_DestroyVoice +#define IXAudio27SourceVoice_ExitLoop FAudioSourceVoice_ExitLoop +#define IXAudio27SourceVoice_FlushSourceBuffers FAudioSourceVoice_FlushSourceBuffers +#define IXAudio27SourceVoice_GetState(a,b) FAudioSourceVoice_GetState(a,b,0) +#define IXAudio27SourceVoice_GetVoiceDetails FAudioVoice_GetVoiceDetails +#define IXAudio27SourceVoice_SetChannelVolumes FAudioVoice_SetChannelVolumes +#define IXAudio27SourceVoice_SetSourceSampleRate FAudioSourceVoice_SetSourceSampleRate +#define IXAudio27SourceVoice_Start FAudioSourceVoice_Start +#define IXAudio27SourceVoice_Stop FAudioSourceVoice_Stop +#define IXAudio27SourceVoice_SubmitSourceBuffer FAudioSourceVoice_SubmitSourceBuffer + +typedef FAudioSourceVoice IXAudio2SourceVoice; +#define IXAudio2SourceVoice_DestroyVoice FAudioVoice_DestroyVoice +#define IXAudio2SourceVoice_ExitLoop FAudioSourceVoice_ExitLoop +#define IXAudio2SourceVoice_FlushSourceBuffers FAudioSourceVoice_FlushSourceBuffers +#define IXAudio2SourceVoice_GetState FAudioSourceVoice_GetState +#define IXAudio2SourceVoice_GetVoiceDetails FAudioVoice_GetVoiceDetails +#define IXAudio2SourceVoice_SetChannelVolumes FAudioVoice_SetChannelVolumes +#define IXAudio2SourceVoice_SetSourceSampleRate FAudioSourceVoice_SetSourceSampleRate +#define IXAudio2SourceVoice_SetVolume FAudioVoice_SetVolume +#define IXAudio2SourceVoice_Start FAudioSourceVoice_Start +#define IXAudio2SourceVoice_Stop FAudioSourceVoice_Stop +#define IXAudio2SourceVoice_SubmitSourceBuffer FAudioSourceVoice_SubmitSourceBuffer + +typedef FAudioSubmixVoice IXAudio27SubmixVoice; +#define IXAudio27SubmixVoice_GetVoiceDetails FAudioVoice_GetVoiceDetails +#define IXAudio27SubmixVoice_DestroyVoice FAudioVoice_DestroyVoice + +typedef FAudioSubmixVoice IXAudio2SubmixVoice; +#define IXAudio2SubmixVoice_GetVoiceDetails FAudioVoice_GetVoiceDetails +#define IXAudio2SubmixVoice_DestroyVoice FAudioVoice_DestroyVoice \ No newline at end of file diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index bddd1776e..ef753cd6f 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -19,12 +19,46 @@ add_library(snd OBJECT sound.c snd_opl.c snd_opl_nuked.c snd_resid.cc snd_azt2316a.c snd_cms.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c) -if(OPENAL OR FAUDIO) - target_compile_definitions(snd PRIVATE USE_OPENAL) - if (FAUDIO) - target_sources(snd PRIVATE faudio.cpp) +if(OPENAL) + if(VCPKG_TOOLCHAIN) + find_package(OpenAL CONFIG REQUIRED) + elseif(MINGW) + find_package(OpenAL MODULE REQUIRED) else() - target_sources(snd PRIVATE openal.c) + find_package(OpenAL REQUIRED) + endif() + + if(TARGET OpenAL::OpenAL) + target_link_libraries(86Box OpenAL::OpenAL) + else() + include_directories(${OPENAL_INCLUDE_DIR}) + target_link_libraries(86Box ${OPENAL_LIBRARY}) + endif() + + target_sources(snd PRIVATE openal.c) +else() + if(WIN32) + option(FAUDIO "Use FAudio instead of XAudio2" OFF) + endif() + + target_sources(snd PRIVATE xaudio2.c) + + if(NOT WIN32 OR FAUDIO) + find_package(PkgConfig REQUIRED) + + # Use FAudio, a reimplementation of XAudio2 + pkg_check_modules(FAUDIO IMPORTED_TARGET FAudio) + if(FAUDIO_FOUND) + target_link_libraries(86Box PkgConfig::FAUDIO) + else() + find_path(FAUDIO_INCLUDE_DIR NAMES "FAudio.h") + find_library(FAUDIO_LIBRARY FAudio) + + include_directories(${FAUDIO_INCLUDE_DIR}) + target_link_libraries(86Box ${FAUDIO_LIBRARY}) + endif() + + set_property(SOURCE xaudio2.c PROPERTY COMPILE_DEFINITIONS USE_FAUDIO) endif() endif() diff --git a/src/sound/faudio.cpp b/src/sound/faudio.cpp deleted file mode 100644 index 246ec0b67..000000000 --- a/src/sound/faudio.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Interface to the FAudio audio processing library. - * - * - * - * Authors: Cacodemon345 - * - * Copyright 2022 Cacodemon345. - */ -#include -#include -#include -#include -#include -#include -#include - -extern "C" -{ -#include <86box/86box.h> -#include <86box/sound.h> -#include <86box/midi.h> - -static int midi_freq = 44100; -static int midi_buf_size = 4410; -static int initialized = 0; -static FAudio* faudio = nullptr; -static FAudioMasteringVoice* mastervoice = nullptr; -static FAudioSourceVoice* srcvoice = nullptr; -static FAudioSourceVoice* srcvoicemidi = nullptr; -static FAudioSourceVoice* srcvoicecd = nullptr; - -#define FREQ 48000 -#define BUFLEN SOUNDBUFLEN - -static void FAUDIOCALL -onBufferFinished( - FAudioVoiceCallback *callback, - void *pBufferContext) -{ - if (sound_is_float) delete[] (float*)(pBufferContext); - else delete[] (int16_t*)(pBufferContext); - -} - -static FAudioVoiceCallback callbacks = -{ - onBufferFinished -}; - -void -inital() -{ - if (FAudioCreate(&faudio, 0, FAUDIO_DEFAULT_PROCESSOR)) - { - return; - } - - if (FAudio_CreateMasteringVoice(faudio, &mastervoice, 2, FREQ, 0, 0, nullptr)) - { - FAudio_Release(faudio); - faudio = nullptr; - return; - } - FAudioWaveFormatEx fmt; - fmt.nChannels = 2; - if (sound_is_float) - { - fmt.wFormatTag = FAUDIO_FORMAT_IEEE_FLOAT; - fmt.wBitsPerSample = 32; - } - else - { - fmt.wFormatTag = FAUDIO_FORMAT_PCM; - fmt.wBitsPerSample = 16; - } - fmt.nSamplesPerSec = FREQ; - fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; - fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; - fmt.cbSize = 0; - if (FAudio_CreateSourceVoice(faudio, &srcvoice, &fmt, 0, 2.0f, &callbacks, nullptr, nullptr)) - { - FAudioVoice_DestroyVoice(mastervoice); - FAudio_Release(faudio); - faudio = nullptr; - mastervoice = nullptr; - return; - } - fmt.nSamplesPerSec = CD_FREQ; - fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; - fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; - FAudio_CreateSourceVoice(faudio, &srcvoicecd, &fmt, 0, 2.0f, &callbacks, nullptr, nullptr); - FAudioVoice_SetVolume(srcvoice, 1, FAUDIO_COMMIT_NOW); - FAudioSourceVoice_Start(srcvoice, 0, FAUDIO_COMMIT_NOW); - FAudioSourceVoice_Start(srcvoicecd, 0, FAUDIO_COMMIT_NOW); - auto mdn = midi_device_get_internal_name(midi_device_current); - if (strcmp(mdn, "none") && strcmp(mdn, SYSTEM_MIDI_INTERNAL_NAME)) - { - fmt.nSamplesPerSec = midi_freq; - fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; - fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; - FAudio_CreateSourceVoice(faudio, &srcvoicemidi, &fmt, 0, 2.0f, &callbacks, nullptr, nullptr); - FAudioSourceVoice_Start(srcvoicemidi, 0, FAUDIO_COMMIT_NOW); - } - initialized = 1; -} - -void -closeal() -{ - if (!initialized) return; - initialized = 0; - FAudioSourceVoice_Stop(srcvoice, 0, FAUDIO_COMMIT_NOW); - FAudioSourceVoice_FlushSourceBuffers(srcvoice); - FAudioSourceVoice_Stop(srcvoicecd, 0, FAUDIO_COMMIT_NOW); - FAudioSourceVoice_FlushSourceBuffers(srcvoicecd); - if (srcvoicemidi) - { - FAudioSourceVoice_Stop(srcvoicemidi, 0, FAUDIO_COMMIT_NOW); - FAudioSourceVoice_FlushSourceBuffers(srcvoicemidi); - FAudioVoice_DestroyVoice(srcvoicemidi); - } - FAudioVoice_DestroyVoice(srcvoice); - FAudioVoice_DestroyVoice(srcvoicecd); - FAudioVoice_DestroyVoice(mastervoice); - FAudio_Release(faudio); - srcvoice = srcvoicecd = srcvoicemidi = nullptr; - mastervoice = nullptr; - faudio = nullptr; -} - -void -givealbuffer_common(void *buf, FAudioSourceVoice* sourcevoice, size_t buflen) -{ - if (!initialized) return; - - FAudioVoice_SetVolume(mastervoice, pow(10.0, (double)sound_gain / 20.0), FAUDIO_COMMIT_NOW); - FAudioBuffer buffer{}; - buffer.Flags = 0; - if (sound_is_float) - { - buffer.pAudioData = (uint8_t*)new float[buflen]; - buffer.AudioBytes = (buflen) * sizeof(float); - } - else - { - buffer.pAudioData = (uint8_t*)new int16_t[buflen]; - buffer.AudioBytes = (buflen) * sizeof(int16_t); - } - if (buffer.pAudioData == nullptr) - { - fatal("faudio: Out Of Memory!"); - } - memcpy((void*)buffer.pAudioData, buf, buffer.AudioBytes); - buffer.PlayBegin = buffer.PlayLength = 0; - buffer.PlayLength = buflen >> 1; - buffer.pContext = (void*)buffer.pAudioData; - FAudioSourceVoice_SubmitSourceBuffer(sourcevoice, &buffer, nullptr); -} - -void -givealbuffer(void *buf) -{ - givealbuffer_common(buf, srcvoice, BUFLEN << 1); -} - -void -givealbuffer_cd(void *buf) -{ - if (srcvoicecd) givealbuffer_common(buf, srcvoicecd, CD_BUFLEN << 1); -} - -void -al_set_midi(int freq, int buf_size) -{ - midi_freq = freq; - midi_buf_size = buf_size; - - if (initialized && srcvoicemidi) - { - FAudioSourceVoice_Stop(srcvoicemidi, 0, FAUDIO_COMMIT_NOW); - FAudioSourceVoice_FlushSourceBuffers(srcvoicemidi); - FAudioVoice_DestroyVoice(srcvoicemidi); - srcvoicemidi = nullptr; - FAudioWaveFormatEx fmt; - fmt.nChannels = 2; - if (sound_is_float) - { - fmt.wFormatTag = FAUDIO_FORMAT_IEEE_FLOAT; - fmt.wBitsPerSample = 32; - } - else - { - fmt.wFormatTag = FAUDIO_FORMAT_PCM; - fmt.wBitsPerSample = 16; - } - fmt.nSamplesPerSec = midi_freq; - fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; - fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; - fmt.cbSize = 0; - FAudio_CreateSourceVoice(faudio, &srcvoicemidi, &fmt, 0, 2.0f, &callbacks, nullptr, nullptr); - FAudioSourceVoice_Start(srcvoicemidi, 0, FAUDIO_COMMIT_NOW); - } -} - -void -givealbuffer_midi(void *buf, uint32_t size) -{ - givealbuffer_common(buf, srcvoicemidi, size); -} - -} \ No newline at end of file diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index ed3e2d535..14093efb4 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -40,10 +40,8 @@ enum fluid_interp { }; -#ifdef USE_OPENAL extern void givealbuffer_midi(void *buf, uint32_t size); extern void al_set_midi(int freq, int buf_size); -#endif static void *fluidsynth_handle; /* handle to FluidSynth DLL */ @@ -152,9 +150,7 @@ static void fluidsynth_thread(void *param) buf_pos += buf_size; if (buf_pos >= data->buf_size) { -#ifdef USE_OPENAL givealbuffer_midi(data->buffer, data->buf_size / sizeof(float)); -#endif buf_pos = 0; } } @@ -167,9 +163,7 @@ static void fluidsynth_thread(void *param) buf_pos += buf_size; if (buf_pos >= data->buf_size) { -#ifdef USE_OPENAL givealbuffer_midi(data->buffer_int16, data->buf_size / sizeof(int16_t)); -#endif buf_pos = 0; } } @@ -322,9 +316,7 @@ void* fluidsynth_init(const device_t *info) data->buffer_int16 = malloc(data->buf_size); } -#ifdef USE_OPENAL al_set_midi(data->samplerate, data->buf_size); -#endif dev = malloc(sizeof(midi_device_t)); memset(dev, 0, sizeof(midi_device_t)); diff --git a/src/sound/midi_mt32.c b/src/sound/midi_mt32.c index 00c26b392..e1812a733 100644 --- a/src/sound/midi_mt32.c +++ b/src/sound/midi_mt32.c @@ -14,10 +14,8 @@ #include <86box/midi.h> -#ifdef USE_OPENAL extern void givealbuffer_midi(void *buf, uint32_t size); extern void al_set_midi(int freq, int buf_size); -#endif static void display_mt32_message(void *instance_data, const char *message); @@ -193,9 +191,7 @@ static void mt32_thread(void *param) buf_pos += bsize; if (buf_pos >= buf_size) { -#ifdef USE_OPENAL givealbuffer_midi(buffer, buf_size / sizeof(float)); -#endif buf_pos = 0; } } @@ -207,9 +203,7 @@ static void mt32_thread(void *param) buf_pos += bsize; if (buf_pos >= buf_size) { -#ifdef USE_OPENAL givealbuffer_midi(buffer_int16, buf_size / sizeof(int16_t)); -#endif buf_pos = 0; } } @@ -261,9 +255,7 @@ void* mt32emu_init(char *control_rom, char *pcm_rom) mt32emu_set_reversed_stereo_enabled(context, device_get_config_int("reversed_stereo")); mt32emu_set_nice_amp_ramp_enabled(context, device_get_config_int("nice_ramp")); -#ifdef USE_OPENAL al_set_midi(samplerate, buf_size); -#endif dev = malloc(sizeof(midi_device_t)); memset(dev, 0, sizeof(midi_device_t)); diff --git a/src/sound/sound.c b/src/sound/sound.c index e12b38bcb..4beab94ba 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -347,12 +347,10 @@ sound_cd_thread(void *param) } } -#ifdef USE_OPENAL if (sound_is_float) givealbuffer_cd(cd_out_buffer); else givealbuffer_cd(cd_out_buffer_int16); -#endif } } @@ -465,12 +463,10 @@ sound_poll(void *priv) } } -#ifdef USE_OPENAL if (sound_is_float) givealbuffer(outbuffer_ex); else givealbuffer(outbuffer_ex_int16); -#endif if (cd_thread_enable) { cd_buf_update--; @@ -499,9 +495,8 @@ sound_reset(void) midi_device_init(); midi_in_device_init(); -#ifdef USE_OPENAL + inital(); -#endif timer_add(&sound_poll_timer, sound_poll, NULL, 1); diff --git a/src/sound/xaudio2.c b/src/sound/xaudio2.c new file mode 100644 index 000000000..8f3329c3b --- /dev/null +++ b/src/sound/xaudio2.c @@ -0,0 +1,279 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Interface to the XAudio2 audio processing library. + * + * + * + * Authors: Cacodemon345 + * + * Copyright 2022 Cacodemon345. + */ +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) && !defined(USE_FAUDIO) +#define COBJMACROS +#include +#else +#include +#include +#endif + +#include <86box/86box.h> +#include <86box/sound.h> +#include <86box/midi.h> +#include <86box/plat_dynld.h> + +#if defined(_WIN32) && !defined(USE_FAUDIO) +static void *xaudio2_handle = NULL; +static HRESULT (WINAPI *pXAudio2Create)(IXAudio2** ppXAudio2, uint32_t Flags, XAUDIO2_PROCESSOR XAudio2Processor); +static dllimp_t xaudio2_imports[] = { + { "XAudio2Create", &pXAudio2Create }, + { NULL, NULL }, +}; +#define XAudio2Create pXAudio2Create +#endif + +static int midi_freq = 44100; +static int midi_buf_size = 4410; +static int initialized = 0; +static IXAudio2 *xaudio2 = NULL; +static IXAudio2MasteringVoice *mastervoice = NULL; +static IXAudio2SourceVoice *srcvoice = NULL; +static IXAudio2SourceVoice *srcvoicemidi = NULL; +static IXAudio2SourceVoice *srcvoicecd = NULL; + +#define FREQ 48000 +#define BUFLEN SOUNDBUFLEN + +static void WINAPI OnVoiceProcessingPassStart(IXAudio2VoiceCallback *callback, uint32_t bytesRequired) {} +static void WINAPI OnVoiceProcessingPassEnd(IXAudio2VoiceCallback *callback) {} +static void WINAPI OnStreamEnd(IXAudio2VoiceCallback *callback) {} +static void WINAPI OnBufferStart(IXAudio2VoiceCallback *callback, void *pBufferContext) {} +static void WINAPI OnLoopEnd(IXAudio2VoiceCallback *callback, void *pBufferContext) {} +static void WINAPI OnVoiceError(IXAudio2VoiceCallback *callback, void *pBufferContext, HRESULT error) {} + +static void WINAPI +OnBufferEnd(IXAudio2VoiceCallback *callback, void *pBufferContext) +{ + free(pBufferContext); +} + +#if defined(_WIN32) && !defined(USE_FAUDIO) +static IXAudio2VoiceCallbackVtbl callbacksVtbl = +#else +static FAudioVoiceCallback callbacks = +#endif +{ + .OnVoiceProcessingPassStart = OnVoiceProcessingPassStart, + .OnVoiceProcessingPassEnd = OnVoiceProcessingPassEnd, + .OnStreamEnd = OnStreamEnd, + .OnBufferStart = OnBufferStart, + .OnBufferEnd = OnBufferEnd, + .OnLoopEnd = OnLoopEnd, + .OnVoiceError = OnVoiceError +}; + +#if defined(_WIN32) && !defined(USE_FAUDIO) +static IXAudio2VoiceCallback callbacks = { &callbacksVtbl }; +#endif + +void +inital() +{ +#if defined(_WIN32) && !defined(USE_FAUDIO) + if (xaudio2_handle == NULL) { + xaudio2_handle = dynld_module("xaudio2_9.dll", xaudio2_imports); + } + + if (xaudio2_handle == NULL) { + xaudio2_handle = dynld_module("xaudio2_9redist.dll", xaudio2_imports); + } + + if (xaudio2_handle == NULL) { + return; + } +#endif + + if (XAudio2Create(&xaudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)) + { + return; + } + + if (IXAudio2_CreateMasteringVoice(xaudio2, &mastervoice, 2, FREQ, 0, 0, NULL, 0)) + { + IXAudio2_Release(xaudio2); + xaudio2 = NULL; + return; + } + + WAVEFORMATEX fmt; + fmt.nChannels = 2; + + if (sound_is_float) + { + fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + fmt.wBitsPerSample = 32; + } + else + { + fmt.wFormatTag = WAVE_FORMAT_PCM; + fmt.wBitsPerSample = 16; + } + + fmt.nSamplesPerSec = FREQ; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; + fmt.cbSize = 0; + + if (IXAudio2_CreateSourceVoice(xaudio2, &srcvoice, &fmt, 0, 2.0f, &callbacks, NULL, NULL)) + { + IXAudio2MasteringVoice_DestroyVoice(mastervoice); + IXAudio2_Release(xaudio2); + xaudio2 = NULL; + mastervoice = NULL; + return; + } + + fmt.nSamplesPerSec = CD_FREQ; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; + + IXAudio2_CreateSourceVoice(xaudio2, &srcvoicecd, &fmt, 0, 2.0f, &callbacks, NULL, NULL); + + IXAudio2SourceVoice_SetVolume(srcvoice, 1, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_Start(srcvoice, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_Start(srcvoicecd, 0, XAUDIO2_COMMIT_NOW); + + char *mdn = midi_device_get_internal_name(midi_device_current); + + if (strcmp(mdn, "none") && strcmp(mdn, SYSTEM_MIDI_INTERNAL_NAME)) + { + fmt.nSamplesPerSec = midi_freq; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; + IXAudio2_CreateSourceVoice(xaudio2, &srcvoicemidi, &fmt, 0, 2.0f, &callbacks, NULL, NULL); + IXAudio2SourceVoice_Start(srcvoicemidi, 0, XAUDIO2_COMMIT_NOW); + } + + initialized = 1; +} + +void +closeal() +{ + if (!initialized) return; + initialized = 0; + IXAudio2SourceVoice_Stop(srcvoice, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(srcvoice); + IXAudio2SourceVoice_Stop(srcvoicecd, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(srcvoicecd); + if (srcvoicemidi) + { + IXAudio2SourceVoice_Stop(srcvoicemidi, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(srcvoicemidi); + IXAudio2SourceVoice_DestroyVoice(srcvoicemidi); + } + IXAudio2SourceVoice_DestroyVoice(srcvoice); + IXAudio2SourceVoice_DestroyVoice(srcvoicecd); + IXAudio2MasteringVoice_DestroyVoice(mastervoice); + IXAudio2_Release(xaudio2); + srcvoice = srcvoicecd = srcvoicemidi = NULL; + mastervoice = NULL; + xaudio2 = NULL; + +#if defined(_WIN32) && !defined(USE_FAUDIO) + dynld_close(xaudio2_handle); + xaudio2_handle = NULL; +#endif +} + +void +givealbuffer_common(void *buf, IXAudio2SourceVoice* sourcevoice, size_t buflen) +{ + if (!initialized) return; + + IXAudio2MasteringVoice_SetVolume(mastervoice, pow(10.0, (double)sound_gain / 20.0), XAUDIO2_COMMIT_NOW); + XAUDIO2_BUFFER buffer = {0}; + buffer.Flags = 0; + if (sound_is_float) + { + buffer.pAudioData = calloc(buflen, sizeof(float)); + buffer.AudioBytes = (buflen) * sizeof(float); + } + else + { + buffer.pAudioData = calloc(buflen, sizeof(int16_t)); + buffer.AudioBytes = (buflen) * sizeof(int16_t); + } + if (buffer.pAudioData == NULL) + { + fatal("xaudio2: Out Of Memory!"); + } + memcpy((void*)buffer.pAudioData, buf, buffer.AudioBytes); + buffer.PlayBegin = buffer.PlayLength = 0; + buffer.PlayLength = buflen >> 1; + buffer.pContext = (void*)buffer.pAudioData; + IXAudio2SourceVoice_SubmitSourceBuffer(sourcevoice, &buffer, NULL); +} + +void +givealbuffer(void *buf) +{ + givealbuffer_common(buf, srcvoice, BUFLEN << 1); +} + +void +givealbuffer_cd(void *buf) +{ + if (srcvoicecd) givealbuffer_common(buf, srcvoicecd, CD_BUFLEN << 1); +} + +void +al_set_midi(int freq, int buf_size) +{ + midi_freq = freq; + midi_buf_size = buf_size; + + if (initialized && srcvoicemidi) + { + IXAudio2SourceVoice_Stop(srcvoicemidi, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(srcvoicemidi); + IXAudio2SourceVoice_DestroyVoice(srcvoicemidi); + srcvoicemidi = NULL; + WAVEFORMATEX fmt; + fmt.nChannels = 2; + if (sound_is_float) + { + fmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + fmt.wBitsPerSample = 32; + } + else + { + fmt.wFormatTag = WAVE_FORMAT_PCM; + fmt.wBitsPerSample = 16; + } + fmt.nSamplesPerSec = midi_freq; + fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; + fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; + fmt.cbSize = 0; + IXAudio2_CreateSourceVoice(xaudio2, &srcvoicemidi, &fmt, 0, 2.0f, &callbacks, NULL, NULL); + IXAudio2SourceVoice_Start(srcvoicemidi, 0, XAUDIO2_COMMIT_NOW); + } +} + +void +givealbuffer_midi(void *buf, uint32_t size) +{ + givealbuffer_common(buf, srcvoicemidi, size); +} diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 3f0b3a3b6..35b06795f 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -173,7 +173,7 @@ ifndef DINPUT DINPUT := n endif ifndef OPENAL -OPENAL := y +OPENAL := n endif ifndef FLUIDSYNTH FLUIDSYNTH := y @@ -373,9 +373,6 @@ else endif endif -ifeq ($(OPENAL), y) -OPTS += -DUSE_OPENAL -endif ifeq ($(FLUIDSYNTH), y) OPTS += -DUSE_FLUIDSYNTH FSYNTHOBJ := midi_fluidsynth.o @@ -645,7 +642,6 @@ PRINTOBJ := png.o prt_cpmap.o \ prt_escp.o prt_text.o prt_ps.o SNDOBJ := sound.o \ - openal.o \ snd_opl.o snd_opl_nuked.o \ snd_resid.o \ convolve.o convolve-sse.o envelope.o extfilt.o \ @@ -736,6 +732,12 @@ else PLATOBJ += win_joystick_rawinput.o endif +ifeq ($(OPENAL), y) + SNDOBJ += openal.o +else + SNDOBJ += xaudio2.o +endif + OBJ := $(MAINOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) $(DEVOBJ) $(MEMOBJ) \ $(FDDOBJ) $(GAMEOBJ) $(CDROMOBJ) $(ZIPOBJ) $(MOOBJ) $(HDDOBJ) $(MINIVHDOBJ) \ $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SIOOBJ) $(SNDOBJ) $(VIDOBJ) $(VOODOOOBJ) \