1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-21 05:53:02 +01:00

Add new audio objects for loading sounds

This commit is contained in:
Ted John
2022-05-09 18:34:38 +01:00
parent 697fa7c436
commit a2e6691ac2
46 changed files with 1583 additions and 1152 deletions

View File

@@ -0,0 +1,220 @@
/*****************************************************************************
* Copyright (c) 2014-2022 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "AudioSampleTable.h"
#include "../Context.h"
#include "../PlatformEnvironment.h"
#include "../audio/AudioContext.h"
#include "../core/Json.hpp"
#include "../core/Path.hpp"
using namespace OpenRCT2;
using namespace OpenRCT2::Audio;
struct SourceInfo
{
std::string Path;
std::vector<int32_t> Range{};
};
static std::vector<int32_t> ParseRange(std::string_view s)
{
// Currently only supports [###] or [###..###]
std::vector<int32_t> result = {};
if (s.length() >= 3 && s[0] == '[' && s[s.length() - 1] == ']')
{
s = s.substr(1, s.length() - 2);
auto parts = String::Split(s, "..");
if (parts.size() == 1)
{
result.push_back(std::stoi(parts[0]));
}
else
{
auto left = std::stoi(parts[0]);
auto right = std::stoi(parts[1]);
if (left <= right)
{
for (auto i = left; i <= right; i++)
{
result.push_back(i);
}
}
else
{
for (auto i = right; i >= left; i--)
{
result.push_back(i);
}
}
}
}
return result;
}
static SourceInfo ParseSource(std::string_view source)
{
SourceInfo info;
if (String::StartsWith(source, "$RCT1:DATA/"))
{
auto name = source.substr(11);
auto rangeStart = name.find('[');
if (rangeStart != std::string::npos)
{
info.Range = ParseRange(name.substr(rangeStart));
name = name.substr(0, rangeStart);
}
auto env = GetContext()->GetPlatformEnvironment();
auto dataPath = env->GetDirectoryPath(DIRBASE::RCT1, DIRID::DATA);
info.Path = Path::Combine(dataPath, name);
}
else if (String::StartsWith(source, "$RCT2:DATA/"))
{
auto name = source.substr(11);
auto rangeStart = name.find('[');
if (rangeStart != std::string::npos)
{
info.Range = ParseRange(name.substr(rangeStart));
name = name.substr(0, rangeStart);
}
auto env = GetContext()->GetPlatformEnvironment();
auto dataPath = env->GetDirectoryPath(DIRBASE::RCT2, DIRID::DATA);
info.Path = Path::Combine(dataPath, name);
}
else if (String::StartsWith(source, "$["))
{
info.Range = ParseRange(source.substr(1));
}
else
{
info.Path = source;
}
return info;
}
void AudioSampleTable::ReadFromJson(IReadObjectContext* context, const json_t& root)
{
json_t jSamples = root["samples"];
if (jSamples.is_array())
{
for (auto& jSample : jSamples)
{
SourceInfo sourceInfo;
int32_t modifier{};
if (jSample.is_string())
{
sourceInfo = ParseSource(jSample.get<std::string>());
}
else if (jSample.is_object())
{
sourceInfo = ParseSource(jSample.at("source").get<std::string>());
if (jSample.contains("modifier"))
{
modifier = jSample.at("modifier").get<int32_t>();
}
}
auto asset = context->GetAsset(sourceInfo.Path);
if (sourceInfo.Range.empty())
{
auto& entry = _entries.emplace_back();
entry.Asset = asset;
entry.Modifier = modifier;
}
else
{
for (auto index : sourceInfo.Range)
{
auto& entry = _entries.emplace_back();
entry.Asset = asset;
entry.PathIndex = index;
entry.Modifier = modifier;
}
}
}
}
}
void AudioSampleTable::LoadFrom(const AudioSampleTable& table, size_t index, size_t length)
{
auto audioContext = GetContext()->GetAudioContext();
auto numEntries = std::min(_entries.size(), length);
for (size_t i = 0; i < numEntries; i++)
{
auto& entry = _entries[i];
if (entry.Source != nullptr)
{
continue;
}
auto sourceIndex = index + i;
if (sourceIndex >= table._entries.size())
{
continue;
}
const auto& sourceEntry = table._entries[sourceIndex];
if (sourceEntry.Asset)
{
auto stream = sourceEntry.Asset->GetStream();
if (stream != nullptr)
{
if (sourceEntry.PathIndex)
{
entry.Source = audioContext->CreateStreamFromCSS(std::move(stream), *sourceEntry.PathIndex);
}
else
{
entry.Source = audioContext->CreateStreamFromWAV(std::move(stream));
}
entry.Modifier = sourceEntry.Modifier;
}
}
}
}
void AudioSampleTable::Load()
{
LoadFrom(*this, 0, _entries.size());
}
void AudioSampleTable::Unload()
{
for (auto& entry : _entries)
{
entry.Source->Release();
entry.Source = nullptr;
}
}
size_t AudioSampleTable::GetCount() const
{
return _entries.size();
}
IAudioSource* AudioSampleTable::GetSample(uint32_t index) const
{
if (index < _entries.size())
{
return _entries[index].Source;
}
return nullptr;
}
int32_t AudioSampleTable::GetSampleModifier(uint32_t index) const
{
if (index < _entries.size())
{
return _entries[index].Modifier;
}
return 0;
}