Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 69 additions & 68 deletions framework/audio/common/audiotypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@

#include "mpe/events.h"

#include "audioplugins/audiopluginstypes.h"

#include "log.h"

namespace muse::audio {
Expand Down Expand Up @@ -167,86 +169,91 @@ struct AudioEngineConfig {
};

using AudioSourceName = std::string;
using AudioResourceId = std::string;
using AudioResourceIdList = std::vector<AudioResourceId>;
using AudioResourceVendor = std::string;
using AudioResourceAttributes = std::map<String, String>;
using AudioUnitConfig = std::map<std::string, std::string>;

static const String PLAYBACK_SETUP_DATA_ATTRIBUTE(u"playbackSetupData");
static const String CATEGORIES_ATTRIBUTE(u"categories");

using AudioResourceId = muse::audioplugins::AudioResourceId;
using AudioResourceIdList = muse::audioplugins::AudioResourceIdList;
using AudioResourceVendor = muse::audioplugins::AudioResourceVendor;
using AudioResourceAttributes = muse::audioplugins::AudioResourceAttributes;
using AudioResourceMeta = muse::audioplugins::AudioResourceMeta;
using AudioResourceMetaList = muse::audioplugins::AudioResourceMetaList;
using AudioResourceMetaSet = muse::audioplugins::AudioResourceMetaSet;

// Wire-format identifiers for the formats the muse audio engine dispatches
// directly. The strings here are the canonical names persisted in the JSON
// plugin cache. VST and MuseSampler also own their own per-module copies of
// the matching string in their respective public headers; a round-trip test
// in muse_audio_tests asserts they stay in sync.
//
// constexpr std::string_view (not inline std::string) so that the values are
// available at compile time and don't participate in static initialization
// order — the RESOURCE_TYPE_NAMES map below depends on them.
inline constexpr std::string_view FLUID_SOUNDFONT_TYPE_NAME = "FluidSoundfont";
inline constexpr std::string_view NATIVE_EFFECT_TYPE_NAME = "NativeEffect";

// audio::AudioResourceType is an audio-engine-internal enum used to dispatch
// synth/fx routing. It is intentionally kept separate from the framework's
// opaque audioplugins::AudioResourceType (a std::string identifier persisted
// by the audioplugins module). Map between them at the boundary via
// resourceTypeFromString() / resourceTypeName(). The enum lists only the
// formats the audio engine actually routes; apps with broader plugin support
// (e.g. Audacity's LV2/AU/Nyquist) define their own enum and bridge.
enum class AudioResourceType {
Undefined = -1,
FluidSoundfont,
VstPlugin,
NativeEffect,
MuseSamplerSoundPack,
Lv2Plugin,
AudioUnit,
NyquistPlugin,
};

static const std::map<AudioResourceType, QString> RESOURCE_TYPE_MAP = {
{ AudioResourceType::Undefined, "undefined" },
{ AudioResourceType::MuseSamplerSoundPack, "muse_sampler_sound_pack" },
{ AudioResourceType::FluidSoundfont, "fluid_soundfont" },
{ AudioResourceType::VstPlugin, "vst_plugin" },
{ AudioResourceType::NativeEffect, "muse_plugin" },
{ AudioResourceType::Lv2Plugin, "lv2_plugin" },
{ AudioResourceType::AudioUnit, "audio_unit" },
{ AudioResourceType::NyquistPlugin, "nyquist_plugin" },
static const std::map<AudioResourceType, std::string> RESOURCE_TYPE_NAMES = {
{ AudioResourceType::FluidSoundfont, std::string(FLUID_SOUNDFONT_TYPE_NAME) },
{ AudioResourceType::VstPlugin, "VstPlugin" },
{ AudioResourceType::NativeEffect, std::string(NATIVE_EFFECT_TYPE_NAME) },
{ AudioResourceType::MuseSamplerSoundPack, "MuseSamplerSoundPack" },
};

struct AudioResourceMeta {
AudioResourceId id;
AudioResourceVendor vendor;
AudioResourceAttributes attributes;
AudioResourceType type = AudioResourceType::Undefined;
bool hasNativeEditorSupport = false;
inline const std::string& resourceTypeName(AudioResourceType type)
{
auto it = RESOURCE_TYPE_NAMES.find(type);
if (it != RESOURCE_TYPE_NAMES.end()) {
return it->second;
}
static const std::string empty;
return empty;
}

const String& attributeVal(const String& key) const
{
auto search = attributes.find(key);
if (search != attributes.cend()) {
return search->second;
inline AudioResourceType resourceTypeFromString(const std::string& name)
{
for (const auto& kv : RESOURCE_TYPE_NAMES) {
if (kv.second == name) {
return kv.first;
}

static String empty;
return empty;
}
return AudioResourceType::Undefined;
}

bool isValid() const
{
return !id.empty()
&& !vendor.empty()
&& type != AudioResourceType::Undefined;
}
inline bool isResourceType(const AudioResourceMeta& meta, AudioResourceType type)
{
return resourceTypeFromString(meta.type) == type;
}

bool operator==(const AudioResourceMeta& other) const
{
return id == other.id
&& vendor == other.vendor
&& type == other.type
&& hasNativeEditorSupport == other.hasNativeEditorSupport
&& attributes == other.attributes;
}
static const String PLAYBACK_SETUP_DATA_ATTRIBUTE(u"playbackSetupData");
static const String HAS_NATIVE_EDITOR_SUPPORT_ATTRIBUTE(u"hasNativeEditorSupport");

bool operator!=(const AudioResourceMeta& other) const
{
return !(*this == other);
}
inline bool hasNativeEditorSupport(const AudioResourceMeta& meta)
{
return muse::audioplugins::boolAttribute(meta, HAS_NATIVE_EDITOR_SUPPORT_ATTRIBUTE);
}

bool operator<(const AudioResourceMeta& other) const
{
return id < other.id
|| vendor < other.vendor;
}
static const std::map<AudioResourceType, QString> RESOURCE_TYPE_MAP = {
{ AudioResourceType::Undefined, "undefined" },
{ AudioResourceType::MuseSamplerSoundPack, "muse_sampler_sound_pack" },
{ AudioResourceType::FluidSoundfont, "fluid_soundfont" },
{ AudioResourceType::VstPlugin, "vst_plugin" },
{ AudioResourceType::NativeEffect, "muse_plugin" },
};

using AudioResourceMetaList = std::vector<AudioResourceMeta>;
using AudioResourceMetaSet = std::set<AudioResourceMeta>;

static const AudioResourceId MUSE_REVERB_ID("Muse Reverb");

enum class AudioFxType {
Expand Down Expand Up @@ -304,14 +311,11 @@ struct AudioFxParams {

AudioFxType type() const
{
switch (resourceMeta.type) {
switch (resourceTypeFromString(resourceMeta.type)) {
case AudioResourceType::VstPlugin: return AudioFxType::VstFx;
case AudioResourceType::NativeEffect: return AudioFxType::MuseFx;
case AudioResourceType::AudioUnit:
case AudioResourceType::Lv2Plugin:
case AudioResourceType::FluidSoundfont:
case AudioResourceType::MuseSamplerSoundPack:
case AudioResourceType::NyquistPlugin:
case AudioResourceType::Undefined: break;
}

Expand Down Expand Up @@ -383,16 +387,13 @@ enum class AudioSourceType {
MuseSampler
};

inline AudioSourceType sourceTypeFromResourceType(AudioResourceType type)
inline AudioSourceType sourceTypeFromResourceType(const muse::audioplugins::AudioResourceType& metaType)
{
switch (type) {
switch (resourceTypeFromString(metaType)) {
case AudioResourceType::FluidSoundfont: return AudioSourceType::Fluid;
case AudioResourceType::VstPlugin: return AudioSourceType::Vsti;
case AudioResourceType::MuseSamplerSoundPack: return AudioSourceType::MuseSampler;
case AudioResourceType::AudioUnit:
case AudioResourceType::Lv2Plugin:
case AudioResourceType::NativeEffect:
case AudioResourceType::NyquistPlugin:
case AudioResourceType::Undefined: break;
}

Expand Down
24 changes: 7 additions & 17 deletions framework/audio/common/audioutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@ inline AudioResourceMeta makeReverbMeta()
{
AudioResourceMeta meta;
meta.id = MUSE_REVERB_ID;
meta.type = AudioResourceType::NativeEffect;
meta.type = NATIVE_EFFECT_TYPE_NAME;
meta.vendor = "Muse";
meta.hasNativeEditorSupport = true;
meta.attributes.emplace(HAS_NATIVE_EDITOR_SUPPORT_ATTRIBUTE, u"true");

return meta;
}

inline String audioResourceTypeToString(const AudioResourceType& type)
inline String audioResourceTypeToString(const muse::audioplugins::AudioResourceType& metaType)
{
AudioResourceType type = resourceTypeFromString(metaType);
auto search = RESOURCE_TYPE_MAP.find(type);

if (search != RESOURCE_TYPE_MAP.end()) {
Expand All @@ -54,7 +55,7 @@ inline String audioSourceName(const AudioInputParams& params)
return params.resourceMeta.attributeVal(u"museName");
}

if (params.resourceMeta.type == audio::AudioResourceType::FluidSoundfont) {
if (isResourceType(params.resourceMeta, AudioResourceType::FluidSoundfont)) {
const String& presetName = params.resourceMeta.attributeVal(synth::PRESET_NAME_ATTRIBUTE);
if (!presetName.empty()) {
return presetName;
Expand Down Expand Up @@ -84,7 +85,7 @@ inline String audioSourceCategoryName(const AudioInputParams& params)
return params.resourceMeta.attributeVal(u"museCategory");
}

if (params.resourceMeta.type == audio::AudioResourceType::FluidSoundfont) {
if (isResourceType(params.resourceMeta, AudioResourceType::FluidSoundfont)) {
return params.resourceMeta.attributeVal(synth::SOUNDFONT_NAME_ATTRIBUTE);
}

Expand All @@ -109,17 +110,6 @@ inline AudioFxCategories audioFxCategoriesFromString(const String& str)

inline bool isOnlineAudioResource(const AudioResourceMeta& meta)
{
const String& attr = meta.attributeVal(u"isOnline");
if (attr.empty()) {
return false;
}

bool ok = true;
const int val = attr.toInt(&ok);
if (!ok) {
return false;
}

return val == 1;
return muse::audioplugins::boolAttribute(meta, u"isOnline");
}
}
4 changes: 2 additions & 2 deletions framework/audio/common/rpc/rpcpacker.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,12 @@ inline void unpack_custom(muse::msgpack::UnPacker& p, muse::audio::AudioFxCatego

inline void pack_custom(muse::msgpack::Packer& p, const muse::audio::AudioResourceMeta& value)
{
p.process(value.id, value.type, value.vendor, value.attributes, value.hasNativeEditorSupport);
p.process(value.id, value.type, value.vendor, value.attributes);
}

inline void unpack_custom(muse::msgpack::UnPacker& p, muse::audio::AudioResourceMeta& value)
{
p.process(value.id, value.type, value.vendor, value.attributes, value.hasNativeEditorSupport);
p.process(value.id, value.type, value.vendor, value.attributes);
}

inline void pack_custom(muse::msgpack::Packer& p, const muse::audio::AudioFxParams& value)
Expand Down
3 changes: 1 addition & 2 deletions framework/audio/engine/internal/audioengineconfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ static const AudioResourceMeta DEFAULT_AUDIO_RESOURCE_META = {
DEFAULT_SOUND_FONT_NAME,
"Fluid",
DEFAULT_AUDIO_RESOURCE_ATTRIBUTES,
AudioResourceType::FluidSoundfont,
false /*hasNativeEditor*/ };
"FluidSoundfont" };
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Use the canonical FLUID_SOUNDFONT_TYPE_NAME constant rather than a raw string literal.

fluidresolver.cpp now sets meta.type = FLUID_SOUNDFONT_TYPE_NAME and enginerpccontroller.cpp dispatches via AudioResourceType::FluidSoundfont. Hard-coding "FluidSoundfont" here duplicates the wire-string and will silently desync if the canonical constant is ever renamed. Prefer referencing the constant so all producers/consumers share one source of truth.

♻️ Proposed fix
-static const AudioResourceMeta DEFAULT_AUDIO_RESOURCE_META = {
-    DEFAULT_SOUND_FONT_NAME,
-    "Fluid",
-    DEFAULT_AUDIO_RESOURCE_ATTRIBUTES,
-    "FluidSoundfont" };
+static const AudioResourceMeta DEFAULT_AUDIO_RESOURCE_META = {
+    DEFAULT_SOUND_FONT_NAME,
+    "Fluid",
+    DEFAULT_AUDIO_RESOURCE_ATTRIBUTES,
+    synth::FLUID_SOUNDFONT_TYPE_NAME };

Adjust the namespace qualifier to match wherever FLUID_SOUNDFONT_TYPE_NAME is declared (likely muse::audio::synth based on the existing include of soundfonttypes.h).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"FluidSoundfont" };
static const AudioResourceMeta DEFAULT_AUDIO_RESOURCE_META = {
DEFAULT_SOUND_FONT_NAME,
"Fluid",
DEFAULT_AUDIO_RESOURCE_ATTRIBUTES,
synth::FLUID_SOUNDFONT_TYPE_NAME };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/audio/engine/internal/audioengineconfiguration.cpp` at line 44, The
literal "FluidSoundfont" should be replaced with the canonical
FLUID_SOUNDFONT_TYPE_NAME constant to avoid duplicating the wire-string; update
the code in audioengineconfiguration.cpp to use the constant (e.g.
muse::audio::synth::FLUID_SOUNDFONT_TYPE_NAME or the correct namespace where
FLUID_SOUNDFONT_TYPE_NAME is declared) and ensure the existing include of
soundfonttypes.h provides that symbol or add the proper include/using directive
so the compiler can find FLUID_SOUNDFONT_TYPE_NAME.


void AudioEngineConfiguration::setConfig(const AudioEngineConfig& conf)
{
Expand Down
4 changes: 1 addition & 3 deletions framework/audio/engine/internal/enginerpccontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,8 @@ void EngineRpcController::init()
}
};

AudioResourceType resourceType = params.source.resourceMeta.type;

// Not Fluid
if (resourceType != AudioResourceType::FluidSoundfont) {
if (!isResourceType(params.source.resourceMeta, AudioResourceType::FluidSoundfont)) {
addTrackAndSendResponse(msg, trackName, playbackData, params);
return make_response_delayed(msg);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,12 @@ void FluidResolver::refresh()

AudioResourceMeta chooseAutomaticMeta;
chooseAutomaticMeta.id = id;
chooseAutomaticMeta.type = AudioResourceType::FluidSoundfont;
chooseAutomaticMeta.type = FLUID_SOUNDFONT_TYPE_NAME;
chooseAutomaticMeta.vendor = FLUID_VENDOR_NAME;
chooseAutomaticMeta.attributes = {
{ PLAYBACK_SETUP_DATA_ATTRIBUTE, muse::mpe::GENERIC_SETUP_DATA_STRING },
{ SOUNDFONT_NAME_ATTRIBUTE, String::fromStdString(soundFont.name) }
};
chooseAutomaticMeta.hasNativeEditorSupport = false;

m_resourcesCache.emplace(id, SoundFontResource { soundFont.path, std::nullopt, std::move(chooseAutomaticMeta) });
}
Expand All @@ -129,7 +128,7 @@ void FluidResolver::refresh()

AudioResourceMeta meta;
meta.id = id;
meta.type = AudioResourceType::FluidSoundfont;
meta.type = FLUID_SOUNDFONT_TYPE_NAME;
meta.vendor = FLUID_VENDOR_NAME;
meta.attributes = {
{ PLAYBACK_SETUP_DATA_ATTRIBUTE, muse::mpe::GENERIC_SETUP_DATA_STRING },
Expand All @@ -138,7 +137,6 @@ void FluidResolver::refresh()
{ PRESET_BANK_ATTRIBUTE, String::number(preset.program.bank) },
{ PRESET_PROGRAM_ATTRIBUTE, String::number(preset.program.program) },
};
meta.hasNativeEditorSupport = false;

m_resourcesCache.emplace(id, SoundFontResource { soundFont.path, preset.program, std::move(meta) });
}
Expand Down
1 change: 1 addition & 0 deletions framework/audio/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ set(MODULE_TEST muse_audio_tests)
set(MODULE_TEST_SRC
${CMAKE_CURRENT_LIST_DIR}/rpcpacker_tests.cpp
${CMAKE_CURRENT_LIST_DIR}/alignbuffer_tests.cpp
${CMAKE_CURRENT_LIST_DIR}/audioresourcetypes_tests.cpp
)

include(SetupGTest)
Loading
Loading