Core Concepts¶
This page explains the key concepts and architecture of Logic Plugin Manager.
Architecture Overview¶
Logic Plugin Manager is structured around three main areas:
Components: Audio Unit plugin bundles and their metadata
Logic Management: High-level interface for plugin discovery and organization
Tags & Categories: Logic Pro’s categorization system
The Library’s Structure¶
logic_plugin_manager/
├── components/ # Audio Unit components
│ ├── AudioComponent # Individual plugin representation
│ ├── Component # .component bundle parser
│ └── AudioUnitType # Audio Unit type enumeration
├── logic/ # Main management interface
│ ├── Logic # Primary entry point
│ ├── Plugins # Plugin collection with search
│ └── SearchResult # Search result with scoring
└── tags/ # Category and tag management
├── Category # Plugin category management
├── MusicApps # Database interface
├── Tagpool # Plugin count tracking
├── Properties # Category sorting
└── Tagset # Plugin tag files
Understanding Audio Components¶
Audio Component Bundle Structure¶
macOS Audio Unit plugins are distributed as .component bundles:
PluginName.component/
└── Contents/
├── Info.plist # Metadata and component definitions
├── MacOS/
│ └── PluginName # Executable binary
└── Resources/ # UI resources, presets, etc.
The Info.plist file contains an AudioComponents array defining one or more Audio Units within the bundle.
AudioComponent Class¶
Each Audio Unit is represented by an AudioComponent instance with:
Identification: Type, subtype, and manufacturer codes
Metadata: Name, description, version
Categories: Tags assigned in Logic Pro
Tags ID: Unique identifier derived from codes
from logic_plugin_manager import Logic
logic = Logic()
plugin = logic.plugins.get_by_name("Pro-Q 3")
# Access component information
print(f"Full Name: {plugin.full_name}")
print(f"Manufacturer: {plugin.manufacturer}")
print(f"Type Code: {plugin.type_code}")
print(f"Subtype Code: {plugin.subtype_code}")
print(f"Manufacturer Code: {plugin.manufacturer_code}")
print(f"Tags ID: {plugin.tags_id}")
Audio Unit Types¶
Logic Plugin Manager recognizes five Audio Unit types:
Code |
Display Name |
Alternative Name |
Description |
|---|---|---|---|
|
Audio FX |
Effect |
Audio effect processors |
|
Instrument |
Music Device |
Software instruments and synthesizers |
|
MIDI-controlled Effects |
Music Effect |
Effects controlled by MIDI input |
|
MIDI FX |
MIDI Generator |
MIDI processors and generators |
|
Generator |
Generator |
Audio generators |
from logic_plugin_manager import AudioUnitType
# Get type by code
instrument_type = AudioUnitType.from_code("aumu")
print(instrument_type.display_name) # "Instrument"
# Search for types
effect_types = AudioUnitType.search("effect")
The Logic Class¶
The Logic class is the main entry point for plugin management.
Initialization Process¶
When you create a Logic instance (with lazy=False, the default):
Loads MusicApps database (tagpool and properties files)
Scans
/Library/Audio/Plug-Ins/ComponentsdirectoryParses each
.componentbundle’sInfo.plistCreates
AudioComponentinstancesLoads tagsets and categories for each plugin
Indexes plugins for fast lookups
from logic_plugin_manager import Logic
# Full initialization
logic = Logic() # Discovers everything
# Lazy initialization (manual control)
logic = Logic(lazy=True)
logic.discover_plugins() # When ready to load plugins
logic.discover_categories() # When ready to load categories
Logic Instance Attributes¶
logic = Logic()
# Access discovered data
logic.plugins # Plugins collection
logic.components # Set of Component bundles
logic.categories # Dict of category_name -> Category
logic.musicapps # MusicApps database interface
# Configuration paths
logic.components_path # Path to Components directory
logic.tags_path # Path to tags database
Plugin Collection & Search¶
The Plugins Class¶
The Plugins class provides a searchable collection with multiple indexes:
By full name: Exact manufacturer + plugin name match
By manufacturer: All plugins from a vendor
By name: Plugin name only
By codes: Type, subtype, manufacturer codes
By category: All plugins in a category
By tags_id: Unique component identifier
logic = Logic()
# Exact lookups (fast)
plugin = logic.plugins.get_by_full_name("fabfilter: pro-q 3")
plugin = logic.plugins.get_by_tags_id("61756678-65517033-46466")
# Set lookups
fabfilter = logic.plugins.get_by_manufacturer("fabfilter")
effects = logic.plugins.get_by_type_code("aufx")
eq_plugins = logic.plugins.get_by_category("Effects:EQ")
Search Algorithm¶
The search() method implements a sophisticated scoring system:
Priority Levels (highest to lowest):
Tags ID exact match (score: 1000)
Name substring match (850-900)
Full name substring match (750-800)
Fuzzy name match (650-700, requires rapidfuzz)
Manufacturer match (580-650)
Category match (480-550)
Type code match (380-450)
Subtype code match (290-350)
Manufacturer code match (190-250)
logic = Logic()
# Fuzzy search with scoring
results = logic.plugins.search(
"serum",
use_fuzzy=True,
fuzzy_threshold=80,
max_results=10
)
for result in results:
print(f"{result.plugin.full_name}")
print(f" Score: {result.score}")
print(f" Matched: {result.match_field}")
MusicApps Database¶
Database Files¶
Logic Pro stores category information in two files:
- MusicApps.tagpool
Maps category names to plugin counts:
{ "Effects": 245, "Effects:EQ": 18, "Instruments": 89, ... }
- MusicApps.properties
Stores category sort order and preferences:
{ "sorting": ["Effects", "Effects:Dynamics", ...], "user_sorted": "property" # or absent for alphabetical }
Accessing the Database¶
logic = Logic()
musicapps = logic.musicapps
# Access tagpool
print(musicapps.tagpool.categories)
# Access properties
print(musicapps.properties.sorting)
print(musicapps.properties.user_sorted)
# Modify database
musicapps.introduce_category("New Category")
musicapps.remove_category("Old Category")
Thread Safety¶
Logic Plugin Manager is not thread-safe. The library performs file I/O operations on Logic Pro’s database files without locking mechanisms.
Recommendations:
Use a single
Logicinstance per processAvoid concurrent writes to categories or tagsets
Reload data after external changes (e.g., Logic Pro modifying categories)
Performance Considerations¶
Initial Discovery¶
Loading all plugins can take several seconds depending on the number of installed components. Use lazy=True for faster startup when you don’t need immediate access.
Indexing¶
The Plugins collection maintains multiple indexes. Reindexing is required if you:
Modify plugin properties externally
Add plugins after initialization
logic = Logic(lazy=True)
logic.discover_plugins()
# ... modify plugins externally ...
logic.plugins.reindex_all()
Search Performance¶
Exact lookups by indexes are O(1)
Fuzzy search with
rapidfuzzis O(n) but optimizedUse
max_resultsto limit computation for large result sets
Best Practices¶
Single Instance: Create one
Logicinstance and reuse itError Handling: Wrap operations in try-except blocks for specific exceptions
Lazy Loading: Use for CLI tools or services that don’t need immediate access
Reloading: Call
load()methods after external modifications to databases
from logic_plugin_manager import (
Logic,
CategoryValidationError,
PluginLoadError
)
try:
logic = Logic()
except PluginLoadError as e:
print(f"Failed to load plugins: {e}")
# Handle gracefully
# Batch operation example
favorites = {
logic.plugins.get_by_name(name)
for name in ["Pro-Q 3", "Serum", "Valhalla VintageVerb"]
if logic.plugins.get_by_name(name)
}
if favorites:
fav_category = logic.introduce_category("Favorites")
logic.add_plugins_to_category(fav_category, favorites)
logic.sync_category_plugin_amount(fav_category)