FAudio audio backend

This commit is contained in:
Cacodemon345
2022-02-19 15:35:10 +06:00
parent d77dd42f8e
commit 09716ae284
4 changed files with 233 additions and 4 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)
target_link_libraries(86Box resid-fp)

219
src/sound/faudio.cpp Normal file
View File

@@ -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 <math.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <FAudio.h>
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);
}
}