proof of concept

This commit is contained in:
goeiecool9999 2023-12-17 02:50:00 +01:00
parent bab1616565
commit a7a116a6f1
9 changed files with 138 additions and 110 deletions

View file

@ -25,6 +25,8 @@
#include "util/helpers/Serializer.h"
#include <wx/msgdlg.h>
#include <audio/IAudioAPI.h>
#include <util/bootSound/BootSoundReader.h>
#if BOOST_OS_WINDOWS
#include <psapi.h>
@ -374,6 +376,25 @@ void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateF
auto lastFrameUpdate = tick_cached();
AudioAPIPtr audioDev;
const sint32 samplesPerBlock = 4800;
const sint32 audioBlockSize = samplesPerBlock * 2 * 2;
try
{
audioDev = IAudioAPI::CreateDeviceFromConfig(true, 48000, 2, samplesPerBlock, 16);
}
catch (const std::runtime_error& ex)
{
cemuLog_log(LogType::Force, "Failed to initialise audio device for bootup sound");
}
audioDev->Play();
std::string sndPath = fmt::format("{}/meta/{}", CafeSystem::GetMlcStoragePath(CafeSystem::GetForegroundTitleId()), "bootSound.btsnd");
sint32 fscStatus = FSC_STATUS_UNDEFINED;
static auto bootsndFile = fsc_open(sndPath.c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);
static BootSoundReader reader{bootsndFile, audioBlockSize};
while (true)
{
if (Latte_GetStopSignal())
@ -495,7 +516,15 @@ void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateF
// finish frame
g_renderer->SwapBuffers(true, true);
if(audioDev && bootsndFile)
{
if (audioDev->NeedAdditionalBlocks())
audioDev->FeedBlock(reader.getSamples());
}
}
audioDev->Stop();
}
void LatteShaderCache_LoadVulkanPipelineCache(uint64 cacheTitleId)

View file

@ -396,90 +396,34 @@ namespace snd_core
void AXOut_init()
{
auto& config = GetConfig();
const auto audio_api = (IAudioAPI::AudioAPI)config.audio_api;
numQueuedFramesSndGeneric = 0;
std::unique_lock lock(g_audioMutex);
if (!g_tvAudio)
{
sint32 channels;
switch (config.tv_channels)
try
{
case 0:
channels = 1; // will mix mono sound on both output channels
break;
case 2:
channels = 6;
break;
default: // stereo
channels = 2;
break;
g_tvAudio = IAudioAPI::CreateDeviceFromConfig(true, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16);
}
IAudioAPI::DeviceDescriptionPtr device_description;
if (IAudioAPI::IsAudioAPIAvailable(audio_api))
catch (std::runtime_error& ex)
{
auto devices = IAudioAPI::GetDevices(audio_api);
const auto it = std::find_if(devices.begin(), devices.end(), [&config](const auto& d) {return d->GetIdentifier() == config.tv_device; });
if (it != devices.end())
device_description = *it;
}
if (device_description)
{
try
{
g_tvAudio = IAudioAPI::CreateDevice((IAudioAPI::AudioAPI)config.audio_api, device_description, 48000, channels, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16);
g_tvAudio->SetVolume(config.tv_volume);
}
catch (std::runtime_error& ex)
{
cemuLog_log(LogType::Force, "can't initialize tv audio: {}", ex.what());
exit(0);
}
cemuLog_log(LogType::Force, "can't initialize tv audio: {}", ex.what());
exit(0);
}
}
if (!g_padAudio)
{
sint32 channels;
switch (config.pad_channels)
try
{
case 0:
channels = 1; // will mix mono sound on both output channels
break;
case 2:
channels = 6;
break;
default: // stereo
channels = 2;
break;
g_padAudio = IAudioAPI::CreateDeviceFromConfig(false, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16);
g_padVolume = g_padAudio->GetVolume();
}
IAudioAPI::DeviceDescriptionPtr device_description;
if (IAudioAPI::IsAudioAPIAvailable(audio_api))
catch (std::runtime_error& ex)
{
auto devices = IAudioAPI::GetDevices(audio_api);
const auto it = std::find_if(devices.begin(), devices.end(), [&config](const auto& d) {return d->GetIdentifier() == config.pad_device; });
if (it != devices.end())
device_description = *it;
}
if (device_description)
{
try
{
g_padAudio = IAudioAPI::CreateDevice((IAudioAPI::AudioAPI)config.audio_api, device_description, 48000, channels, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16);
g_padAudio->SetVolume(config.pad_volume);
g_padVolume = config.pad_volume;
}
catch (std::runtime_error& ex)
{
cemuLog_log(LogType::Force, "can't initialize pad audio: {}", ex.what());
exit(0);
}
cemuLog_log(LogType::Force, "can't initialize pad audio: {}", ex.what());
exit(0);
}
}
}

View file

@ -97,7 +97,37 @@ bool IAudioAPI::IsAudioAPIAvailable(AudioAPI api)
return false;
}
AudioAPIPtr IAudioAPI::CreateDeviceFromConfig(bool TV, sint32 rate, sint32 samples_per_block, sint32 bits_per_sample)
{
auto& config = GetConfig();
sint32 channels = CemuConfig::AudioChannelsToNChannels(TV ? config.tv_channels : config.pad_channels);
return CreateDeviceFromConfig(TV, rate, channels, samples_per_block, bits_per_sample);
}
AudioAPIPtr IAudioAPI::CreateDeviceFromConfig(bool TV, sint32 rate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample)
{
AudioAPIPtr audioAPIDev;
auto& config = GetConfig();
const auto audio_api = (IAudioAPI::AudioAPI)config.audio_api;
auto& selectedDevice = TV ? config.tv_device : config.pad_device;
IAudioAPI::DeviceDescriptionPtr device_description;
if (IAudioAPI::IsAudioAPIAvailable(audio_api))
{
auto devices = IAudioAPI::GetDevices(audio_api);
const auto it = std::find_if(devices.begin(), devices.end(), [&selectedDevice](const auto& d) {return d->GetIdentifier() == selectedDevice; });
if (it != devices.end())
device_description = *it;
}
if (!device_description)
throw std::runtime_error("failed to find selected device while trying to create audio device");
audioAPIDev = CreateDevice(audio_api, device_description, rate, channels, samples_per_block, bits_per_sample);
audioAPIDev->SetVolume(TV ? config.tv_volume : config.pad_volume);
return audioAPIDev;
}
AudioAPIPtr IAudioAPI::CreateDevice(AudioAPI api, const DeviceDescriptionPtr& device, sint32 samplerate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample)
{

View file

@ -59,7 +59,9 @@ public:
static void PrintLogging();
static void InitializeStatic();
static bool IsAudioAPIAvailable(AudioAPI api);
static std::unique_ptr<IAudioAPI> CreateDeviceFromConfig(bool TV, sint32 rate, sint32 samples_per_block, sint32 bits_per_sample);
static std::unique_ptr<IAudioAPI> CreateDeviceFromConfig(bool TV, sint32 rate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample);
static std::unique_ptr<IAudioAPI> CreateDevice(AudioAPI api, const DeviceDescriptionPtr& device, sint32 samplerate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample);
static std::vector<DeviceDescriptionPtr> GetDevices(AudioAPI api);

View file

@ -507,6 +507,19 @@ struct CemuConfig
bool GetGameListCustomName(uint64 titleId, std::string& customName);
void SetGameListCustomName(uint64 titleId, std::string customName);
static int AudioChannelsToNChannels(AudioChannels kStereo)
{
switch (kStereo)
{
case 0:
return 1; // will mix mono sound on both output channels
case 2:
return 6;
default: // stereo
return 2;
}
}
private:
GameEntry* GetGameEntryByTitleId(uint64 titleId);
GameEntry* CreateGameEntry(uint64 titleId);

View file

@ -1734,20 +1734,7 @@ void GeneralSettings2::UpdateAudioDevice()
if (m_game_launched && g_tvAudio)
channels = g_tvAudio->GetChannels();
else
{
switch (config.tv_channels)
{
case 0:
channels = 1;
break;
case 2:
channels = 6;
break;
default: // stereo
channels = 2;
break;
}
}
channels = CemuConfig::AudioChannelsToNChannels(config.tv_channels);
try
{
@ -1782,20 +1769,7 @@ void GeneralSettings2::UpdateAudioDevice()
if (m_game_launched && g_padAudio)
channels = g_padAudio->GetChannels();
else
{
switch (config.pad_channels)
{
case 0:
channels = 1;
break;
case 2:
channels = 6;
break;
default: // stereo
channels = 2;
break;
}
}
channels = CemuConfig::AudioChannelsToNChannels(config.tv_channels);
try
{
@ -1831,20 +1805,7 @@ void GeneralSettings2::UpdateAudioDevice()
if (m_game_launched && g_inputAudio)
channels = g_inputAudio->GetChannels();
else
{
switch (config.input_channels)
{
case 0:
channels = 1;
break;
case 2:
channels = 6;
break;
default: // stereo
channels = 2;
break;
}
}
channels = CemuConfig::AudioChannelsToNChannels(config.input_channels);
try
{

View file

@ -1,5 +1,7 @@
add_library(CemuUtil
boost/bluetooth.h
bootSound/BootSoundReader.cpp
bootSound/BootSoundReader.h
ChunkedHeap/ChunkedHeap.h
containers/flat_hash_map.hpp
containers/IntervalBucketContainer.h

View file

@ -0,0 +1,27 @@
#include "BootSoundReader.h"
#include "Cafe/CafeSystem.h"
BootSoundReader::BootSoundReader(FSCVirtualFile* bootsndFile, sint32 blockSize) : bootsndFile(bootsndFile), blockSize(blockSize)
{
fsc_setFileSeek(bootsndFile, 0);
fsc_readFile(bootsndFile, &muteBits, 4);
fsc_readFile(bootsndFile, &loopPoint, 4);
buffer.resize(blockSize / sizeof(sint16));
bufferBE.resize(blockSize / sizeof(sint16be));
if(blockSize % sizeof(sint16be) != 0)
cemu_assert_suspicious();
}
sint16* BootSoundReader::getSamples()
{
auto read = fsc_readFile(bootsndFile, bufferBE.data(), blockSize);
if(read % sizeof(sint16be) != 0)
cemu_assert_suspicious();
auto readValues = read / sizeof(sint16be);
if (readValues < blockSize)
std::fill(buffer.begin() + readValues, buffer.end(), 0);
std::copy_n(bufferBE.begin(), read / sizeof(sint16be), buffer.begin());
return buffer.data();
}

View file

@ -0,0 +1,20 @@
#pragma once
#include "Cafe/Filesystem/fsc.h"
class BootSoundReader
{
public:
BootSoundReader() = delete;
BootSoundReader(FSCVirtualFile* bootsndFile, sint32 blockSize);
sint16* getSamples();
private:
FSCVirtualFile* bootsndFile{};
sint32 blockSize{};
uint32be muteBits{};
uint32be loopPoint{};
std::vector<sint16> buffer{};
std::vector<sint16be> bufferBE{};
};