From 09716ae28434c955b75c38c6d49c22c32cd23ce5 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 19 Feb 2022 15:35:10 +0600 Subject: [PATCH] FAudio audio backend --- CMakeLists.txt | 1 + src/CMakeLists.txt | 7 +- src/sound/CMakeLists.txt | 10 +- src/sound/faudio.cpp | 219 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 src/sound/faudio.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index baebe22b8..38df9646e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,6 +115,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(FLUIDSYNTH "FluidSynth" ON) option(MUNT "MUNT" ON) option(DINPUT "DirectInput" OFF) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 704024067..ba0cffc7d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -86,7 +86,12 @@ if(APPLE) target_link_libraries(86Box Freetype::Freetype) endif() -if(OPENAL) +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) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index 8879b0378..bddd1776e 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -19,9 +19,13 @@ 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) +if(OPENAL OR FAUDIO) target_compile_definitions(snd PRIVATE USE_OPENAL) - target_sources(snd PRIVATE openal.c) + if (FAUDIO) + target_sources(snd PRIVATE faudio.cpp) + else() + target_sources(snd PRIVATE openal.c) + endif() endif() if(FLUIDSYNTH) @@ -60,4 +64,4 @@ if(TANDY_ISA) endif() add_subdirectory(resid-fp) -target_link_libraries(86Box resid-fp) \ No newline at end of file +target_link_libraries(86Box resid-fp) diff --git a/src/sound/faudio.cpp b/src/sound/faudio.cpp new file mode 100644 index 000000000..246ec0b67 --- /dev/null +++ b/src/sound/faudio.cpp @@ -0,0 +1,219 @@ +/* + * 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