feat(audio): suport d'efectes (eco i reverb) per a sons puntuals
Afig una capa d'efectes oberta a la unitat d'àudio. Els sons puntuals
es poden reproduir processats per un eco o un reverb (Freeverb 8C/4AP)
sense afectar la música ni canviar el camí ràpid existent (playSound
sense efecte segueix sent una sola crida sense cost extra).
- data/sounds.yaml: catàleg de presets nominats (echo: cave/short,
reverb: stone_hall/small_room).
- core/audio/audio_effects: processadors purs que prenen un Ja::Sound
(U8/S16, mono o estèreo) i tornen PCM S16 amb la cua de l'efecte
(cap a 800 ms eco, 1500 ms reverb).
- core/audio/sound_effects_config: Meyers singleton que parseja
sounds.yaml a EchoParams/ReverbParams indexats per nom; l'API
pública d'Audio fa el lookup per nom.
- jail_audio::Engine: nou camí playSoundWith{Echo,Reverb} que empenta
el buffer ja processat a un canal lliure marcat com a has_effect.
El cap MAX_EFFECT_CHANNELS limita a 4 sons amb efecte simultanis;
si està al límit, l'engine retorna -1 i Audio cau a la versió seca.
- Audio::playSoundWith{Echo,Reverb}(name, preset, group) com a única
via pública. Si el preset no existeix, fallback dry amb avís.
- director: load("data/sounds.yaml") abans d'Audio::init.
This commit is contained in:
1 parent
42062dca55
commit
d3698a1504
11 files changed
+593
-5
No files matched your search
@@ -0,0 +1,77 @@
|
||||
#include "core/audio/sound_effects_config.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "core/resources/resource_helper.hpp"
|
||||
#include "external/fkyaml_node.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
// Lector de camp amb fallback: deixa el destí intacte si la clau no
|
||||
// existeix (els defaults dels Ja::*Params s'inicialitzen al ctor del
|
||||
// struct, així que el comportament és "preset parcial = preset complet
|
||||
// amb defaults per als camps que falten").
|
||||
template <typename T>
|
||||
void readField(const fkyaml::node& node, const char* key, T& dst) {
|
||||
if (node.contains(key)) { dst = node[key].get_value<T>(); }
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
auto SoundEffectsConfig::get() -> SoundEffectsConfig& {
|
||||
static SoundEffectsConfig instance_;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void SoundEffectsConfig::load(const std::string& file_path) {
|
||||
auto bytes = Resource::Helper::loadFile(file_path);
|
||||
if (bytes.empty()) {
|
||||
std::cerr << "SoundEffectsConfig: no s'ha pogut obrir " << file_path << " — cap preset d'efecte disponible\n";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const auto* begin = reinterpret_cast<const char*>(bytes.data());
|
||||
const auto* end = begin + bytes.size();
|
||||
auto yaml = fkyaml::node::deserialize(begin, end);
|
||||
|
||||
if (yaml.contains("echo") && yaml["echo"].is_mapping()) {
|
||||
for (auto it = yaml["echo"].begin(); it != yaml["echo"].end(); ++it) {
|
||||
const auto NAME = it.key().get_value<std::string>();
|
||||
const auto& node = it.value();
|
||||
Ja::EchoParams params{};
|
||||
readField(node, "delay_ms", params.delay_ms);
|
||||
readField(node, "feedback", params.feedback);
|
||||
readField(node, "wet", params.wet);
|
||||
echoes_[NAME] = params;
|
||||
}
|
||||
}
|
||||
|
||||
if (yaml.contains("reverb") && yaml["reverb"].is_mapping()) {
|
||||
for (auto it = yaml["reverb"].begin(); it != yaml["reverb"].end(); ++it) {
|
||||
const auto NAME = it.key().get_value<std::string>();
|
||||
const auto& node = it.value();
|
||||
Ja::ReverbParams params{};
|
||||
readField(node, "room_size", params.room_size);
|
||||
readField(node, "damping", params.damping);
|
||||
readField(node, "wet", params.wet);
|
||||
reverbs_[NAME] = params;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "SoundEffectsConfig: " << echoes_.size() << " preset(s) d'eco i " << reverbs_.size() << " de reverb des de " << file_path << '\n';
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "SoundEffectsConfig: error parsejant " << file_path << ": " << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
auto SoundEffectsConfig::findEcho(const std::string& name) const -> const Ja::EchoParams* {
|
||||
const auto IT = echoes_.find(name);
|
||||
return (IT == echoes_.end()) ? nullptr : &IT->second;
|
||||
}
|
||||
|
||||
auto SoundEffectsConfig::findReverb(const std::string& name) const -> const Ja::ReverbParams* {
|
||||
const auto IT = reverbs_.find(name);
|
||||
return (IT == reverbs_.end()) ? nullptr : &IT->second;
|
||||
}
|
||||
Reference in new issue
Block a user