mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-07 23:41:18 +12:00
proof of concept
This commit is contained in:
parent
bab1616565
commit
a7a116a6f1
9 changed files with 138 additions and 110 deletions
|
@ -25,6 +25,8 @@
|
||||||
#include "util/helpers/Serializer.h"
|
#include "util/helpers/Serializer.h"
|
||||||
|
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
|
#include <audio/IAudioAPI.h>
|
||||||
|
#include <util/bootSound/BootSoundReader.h>
|
||||||
|
|
||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
|
@ -374,6 +376,25 @@ void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateF
|
||||||
|
|
||||||
auto lastFrameUpdate = tick_cached();
|
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)
|
while (true)
|
||||||
{
|
{
|
||||||
if (Latte_GetStopSignal())
|
if (Latte_GetStopSignal())
|
||||||
|
@ -495,7 +516,15 @@ void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateF
|
||||||
|
|
||||||
// finish frame
|
// finish frame
|
||||||
g_renderer->SwapBuffers(true, true);
|
g_renderer->SwapBuffers(true, true);
|
||||||
|
|
||||||
|
if(audioDev && bootsndFile)
|
||||||
|
{
|
||||||
|
if (audioDev->NeedAdditionalBlocks())
|
||||||
|
audioDev->FeedBlock(reader.getSamples());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
audioDev->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LatteShaderCache_LoadVulkanPipelineCache(uint64 cacheTitleId)
|
void LatteShaderCache_LoadVulkanPipelineCache(uint64 cacheTitleId)
|
||||||
|
|
|
@ -396,90 +396,34 @@ namespace snd_core
|
||||||
|
|
||||||
void AXOut_init()
|
void AXOut_init()
|
||||||
{
|
{
|
||||||
auto& config = GetConfig();
|
|
||||||
const auto audio_api = (IAudioAPI::AudioAPI)config.audio_api;
|
|
||||||
|
|
||||||
numQueuedFramesSndGeneric = 0;
|
numQueuedFramesSndGeneric = 0;
|
||||||
|
|
||||||
std::unique_lock lock(g_audioMutex);
|
std::unique_lock lock(g_audioMutex);
|
||||||
if (!g_tvAudio)
|
if (!g_tvAudio)
|
||||||
{
|
{
|
||||||
sint32 channels;
|
try
|
||||||
switch (config.tv_channels)
|
|
||||||
{
|
{
|
||||||
case 0:
|
g_tvAudio = IAudioAPI::CreateDeviceFromConfig(true, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16);
|
||||||
channels = 1; // will mix mono sound on both output channels
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
channels = 6;
|
|
||||||
break;
|
|
||||||
default: // stereo
|
|
||||||
channels = 2;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
catch (std::runtime_error& ex)
|
||||||
IAudioAPI::DeviceDescriptionPtr device_description;
|
|
||||||
if (IAudioAPI::IsAudioAPIAvailable(audio_api))
|
|
||||||
{
|
{
|
||||||
auto devices = IAudioAPI::GetDevices(audio_api);
|
cemuLog_log(LogType::Force, "can't initialize tv audio: {}", ex.what());
|
||||||
const auto it = std::find_if(devices.begin(), devices.end(), [&config](const auto& d) {return d->GetIdentifier() == config.tv_device; });
|
exit(0);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_padAudio)
|
if (!g_padAudio)
|
||||||
{
|
{
|
||||||
sint32 channels;
|
try
|
||||||
switch (config.pad_channels)
|
|
||||||
{
|
{
|
||||||
case 0:
|
g_padAudio = IAudioAPI::CreateDeviceFromConfig(false, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16);
|
||||||
channels = 1; // will mix mono sound on both output channels
|
g_padVolume = g_padAudio->GetVolume();
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
channels = 6;
|
|
||||||
break;
|
|
||||||
default: // stereo
|
|
||||||
channels = 2;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
catch (std::runtime_error& ex)
|
||||||
IAudioAPI::DeviceDescriptionPtr device_description;
|
|
||||||
if (IAudioAPI::IsAudioAPIAvailable(audio_api))
|
|
||||||
{
|
{
|
||||||
auto devices = IAudioAPI::GetDevices(audio_api);
|
cemuLog_log(LogType::Force, "can't initialize pad audio: {}", ex.what());
|
||||||
const auto it = std::find_if(devices.begin(), devices.end(), [&config](const auto& d) {return d->GetIdentifier() == config.pad_device; });
|
exit(0);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,37 @@ bool IAudioAPI::IsAudioAPIAvailable(AudioAPI api)
|
||||||
return false;
|
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)
|
AudioAPIPtr IAudioAPI::CreateDevice(AudioAPI api, const DeviceDescriptionPtr& device, sint32 samplerate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample)
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,7 +59,9 @@ public:
|
||||||
static void PrintLogging();
|
static void PrintLogging();
|
||||||
static void InitializeStatic();
|
static void InitializeStatic();
|
||||||
static bool IsAudioAPIAvailable(AudioAPI api);
|
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::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);
|
static std::vector<DeviceDescriptionPtr> GetDevices(AudioAPI api);
|
||||||
|
|
||||||
|
|
|
@ -507,6 +507,19 @@ struct CemuConfig
|
||||||
bool GetGameListCustomName(uint64 titleId, std::string& customName);
|
bool GetGameListCustomName(uint64 titleId, std::string& customName);
|
||||||
void SetGameListCustomName(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:
|
private:
|
||||||
GameEntry* GetGameEntryByTitleId(uint64 titleId);
|
GameEntry* GetGameEntryByTitleId(uint64 titleId);
|
||||||
GameEntry* CreateGameEntry(uint64 titleId);
|
GameEntry* CreateGameEntry(uint64 titleId);
|
||||||
|
|
|
@ -1734,20 +1734,7 @@ void GeneralSettings2::UpdateAudioDevice()
|
||||||
if (m_game_launched && g_tvAudio)
|
if (m_game_launched && g_tvAudio)
|
||||||
channels = g_tvAudio->GetChannels();
|
channels = g_tvAudio->GetChannels();
|
||||||
else
|
else
|
||||||
{
|
channels = CemuConfig::AudioChannelsToNChannels(config.tv_channels);
|
||||||
switch (config.tv_channels)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
channels = 1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
channels = 6;
|
|
||||||
break;
|
|
||||||
default: // stereo
|
|
||||||
channels = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1782,20 +1769,7 @@ void GeneralSettings2::UpdateAudioDevice()
|
||||||
if (m_game_launched && g_padAudio)
|
if (m_game_launched && g_padAudio)
|
||||||
channels = g_padAudio->GetChannels();
|
channels = g_padAudio->GetChannels();
|
||||||
else
|
else
|
||||||
{
|
channels = CemuConfig::AudioChannelsToNChannels(config.tv_channels);
|
||||||
switch (config.pad_channels)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
channels = 1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
channels = 6;
|
|
||||||
break;
|
|
||||||
default: // stereo
|
|
||||||
channels = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1831,20 +1805,7 @@ void GeneralSettings2::UpdateAudioDevice()
|
||||||
if (m_game_launched && g_inputAudio)
|
if (m_game_launched && g_inputAudio)
|
||||||
channels = g_inputAudio->GetChannels();
|
channels = g_inputAudio->GetChannels();
|
||||||
else
|
else
|
||||||
{
|
channels = CemuConfig::AudioChannelsToNChannels(config.input_channels);
|
||||||
switch (config.input_channels)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
channels = 1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
channels = 6;
|
|
||||||
break;
|
|
||||||
default: // stereo
|
|
||||||
channels = 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
add_library(CemuUtil
|
add_library(CemuUtil
|
||||||
boost/bluetooth.h
|
boost/bluetooth.h
|
||||||
|
bootSound/BootSoundReader.cpp
|
||||||
|
bootSound/BootSoundReader.h
|
||||||
ChunkedHeap/ChunkedHeap.h
|
ChunkedHeap/ChunkedHeap.h
|
||||||
containers/flat_hash_map.hpp
|
containers/flat_hash_map.hpp
|
||||||
containers/IntervalBucketContainer.h
|
containers/IntervalBucketContainer.h
|
||||||
|
|
27
src/util/bootSound/BootSoundReader.cpp
Normal file
27
src/util/bootSound/BootSoundReader.cpp
Normal 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();
|
||||||
|
}
|
20
src/util/bootSound/BootSoundReader.h
Normal file
20
src/util/bootSound/BootSoundReader.h
Normal 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{};
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue