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 <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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
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