05_14_05 - Preset Browser¶
Overview¶
The Preset Browser provides fast, flexible searching and browsing of preset collections with:
- Full-text search - Search by name, description, tags, author
- Advanced filtering - Filter by category, module type, version, ratings
- Smart indexing - Fast lookups with inverted index
- Fuzzy matching - Find presets even with typos
- Tag-based search - Multi-tag queries with AND/OR logic
- Favorites system - Mark and quickly access favorite presets
- Recent/Popular tracking - Track usage patterns
- Preview system - Quick preset previews without loading
Architecture¶
┌─────────────────────────────────────────────────────────────────┐
│ Preset Browser │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Search Engine │ │
│ │ │ │
│ │ • Full-text search • Fuzzy matching │ │
│ │ • Tag queries • Ranking algorithm │ │
│ │ • Query parser • Result scoring │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Indexing System │ │
│ │ │ │
│ │ • Inverted index • Metadata index │ │
│ │ • Tag index • Incremental updates │ │
│ │ • Category index • Persistence │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Preset Database │ │
│ │ │ │
│ │ • In-memory storage • Fast lookups │ │
│ │ • Lazy loading • Caching │ │
│ │ • Batch operations • Statistics │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Filter & Sort System │ │
│ │ │ │
│ │ • Multiple filters • Custom sort orders │ │
│ │ • Filter combinations • Pagination │ │
│ │ • Saved filters • Result limiting │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Components¶
1. SearchEngine¶
Fast full-text search with ranking:
SearchEngine engine;
// Load presets into engine
engine.indexPresets(all_presets);
// Simple text search
auto results = engine.search("warm pad");
// Advanced query with filters
SearchQuery query;
query.text = "bass";
query.categories = {"Bass", "Sub Bass"};
query.module_types = {ModuleType::L1_Atom};
query.min_rating = 4.0f;
query.fuzzy_match = true;
auto results = engine.search(query);
// Results are ranked by relevance
for (const auto& result : results) {
std::cout << result.preset.header.name
<< " (score: " << result.score << ")\n";
}
Search Features: - Full-text search across name, description, tags, author - Fuzzy matching with configurable threshold - Tag-based queries (AND/OR logic) - Phrase matching ("warm pad" vs warm OR pad) - Wildcard support (bass*) - Result ranking by relevance
2. IndexingSystem¶
Efficient indexing for fast searches:
IndexingSystem indexer;
// Build index from presets
indexer.buildIndex(presets);
// Incremental update (add new preset)
indexer.indexPreset(new_preset);
// Query index directly
auto preset_ids = indexer.lookup("bass"); // All presets mentioning "bass"
// Tag queries
auto tagged = indexer.findByTags({"synth", "warm"}, TagQuery::AND);
// Category queries
auto in_category = indexer.findByCategory("Lead");
// Save/load index for persistence
indexer.saveIndex("preset_index.bin");
indexer.loadIndex("preset_index.bin");
Index Types: - Inverted Index - Word → Preset IDs (for text search) - Tag Index - Tag → Preset IDs (for tag queries) - Category Index - Category → Preset IDs (for filters) - Metadata Index - Quick lookups by author, version, etc.
3. PresetDatabase¶
Central storage and management:
PresetDatabase db;
// Load presets from various sources
db.loadFromDirectory("factory_presets/");
db.loadFromFile("user_bank.json");
// Query database
auto preset = db.getPresetByID("preset_123");
auto presets = db.getPresetsByCategory("Bass");
// Statistics
std::cout << "Total presets: " << db.getPresetCount() << "\n";
std::cout << "Categories: " << db.getCategoryCount() << "\n";
// Favorites
db.addToFavorites("preset_123");
auto favorites = db.getFavorites();
// Recent presets
db.markAsUsed("preset_123");
auto recent = db.getRecentPresets(10);
// Popular presets
auto popular = db.getPopularPresets(20);
Database Features: - In-memory storage with fast lookups - Lazy loading (load metadata first, full preset on demand) - LRU cache for recently accessed presets - Usage tracking (recent, popular, favorites) - Batch operations - Statistics and analytics
4. FilterSystem¶
Flexible filtering and sorting:
FilterSystem filter_system;
// Create filter
PresetFilter filter;
filter.categories = {"Bass", "Lead"};
filter.module_types = {ModuleType::L1_Atom};
filter.min_version = PresetSchema::Version{1, 0, 0};
filter.max_version = PresetSchema::Version{2, 0, 0};
filter.has_resources = false; // Only presets without external resources
filter.tags_any = {"warm", "analog"}; // Has "warm" OR "analog"
filter.tags_all = {"synth"}; // Must have "synth"
// Apply filter
auto filtered = filter_system.applyFilter(all_presets, filter);
// Sort results
SortOptions sort;
sort.field = SortField::Name;
sort.order = SortOrder::Ascending;
auto sorted = filter_system.sort(filtered, sort);
// Pagination
auto page = filter_system.paginate(sorted, 20, 2); // 20 per page, page 2
// Save filter for later
filter_system.saveFilter("my_bass_sounds", filter);
auto loaded_filter = filter_system.loadFilter("my_bass_sounds");
Filter Options: - Category (multi-select) - Module type - Version range - Rating range - Author - Has resources (yes/no) - Tag matching (any/all) - Date range - Custom predicates
Sort Options: - Name (A-Z, Z-A) - Date created - Date modified - Rating - Usage count - Relevance (from search) - Random
5. PresetPreview¶
Quick preview without full loading:
PresetPreview preview_system(resource_manager);
// Get preview info
auto preview = preview_system.getPreview("preset_123");
std::cout << "Name: " << preview.name << "\n";
std::cout << "Category: " << preview.category << "\n";
std::cout << "Tags: " << join(preview.tags) << "\n";
std::cout << "Key parameters:\n";
for (const auto& [name, value] : preview.key_parameters) {
std::cout << " " << name << ": " << value << "\n";
}
// Get thumbnail (if available)
if (preview.has_thumbnail) {
auto thumbnail = preview_system.getThumbnail("preset_123");
// Display thumbnail...
}
// Get audio preview (if available)
if (preview.has_audio_preview) {
auto audio = preview_system.getAudioPreview("preset_123");
// Play audio preview...
}
API Reference¶
SearchEngine¶
class SearchEngine {
public:
// Indexing
void indexPresets(const std::vector<PresetSchema>& presets);
void indexPreset(const PresetSchema& preset);
void removePreset(const std::string& preset_id);
void clearIndex();
// Search
std::vector<SearchResult> search(const std::string& query);
std::vector<SearchResult> search(const SearchQuery& query);
// Configuration
void setFuzzyThreshold(float threshold);
void setMaxResults(size_t max);
void setRankingWeights(const RankingWeights& weights);
// Statistics
size_t getIndexedPresetCount() const;
size_t getIndexSize() const;
};
struct SearchQuery {
std::string text;
std::vector<std::string> categories;
std::vector<ModuleType> module_types;
std::vector<std::string> tags_all; // AND
std::vector<std::string> tags_any; // OR
std::optional<float> min_rating;
bool fuzzy_match = false;
size_t max_results = 100;
};
struct SearchResult {
PresetSchema preset;
float score; // Relevance score (0.0 to 1.0)
std::string snippet; // Text snippet showing match
};
PresetDatabase¶
class PresetDatabase {
public:
// Loading
void loadFromDirectory(const std::string& path, bool recursive = true);
void loadFromFile(const std::string& path);
void addPreset(const PresetSchema& preset);
void addPresets(const std::vector<PresetSchema>& presets);
// Queries
std::optional<PresetSchema> getPresetByID(const std::string& id);
std::vector<PresetSchema> getPresetsByCategory(const std::string& category);
std::vector<PresetSchema> getPresetsByAuthor(const std::string& author);
std::vector<PresetSchema> getPresetsByTag(const std::string& tag);
std::vector<PresetSchema> getAllPresets();
// Favorites
void addToFavorites(const std::string& preset_id);
void removeFromFavorites(const std::string& preset_id);
bool isFavorite(const std::string& preset_id) const;
std::vector<PresetSchema> getFavorites();
// Usage tracking
void markAsUsed(const std::string& preset_id);
std::vector<PresetSchema> getRecentPresets(size_t count);
std::vector<PresetSchema> getPopularPresets(size_t count);
// Statistics
size_t getPresetCount() const;
size_t getCategoryCount() const;
std::vector<std::string> getAllCategories() const;
std::vector<std::string> getAllTags() const;
std::map<std::string, size_t> getCategoryDistribution() const;
std::map<std::string, size_t> getTagDistribution() const;
};
FilterSystem¶
class FilterSystem {
public:
// Filtering
std::vector<PresetSchema> applyFilter(
const std::vector<PresetSchema>& presets,
const PresetFilter& filter);
// Sorting
std::vector<PresetSchema> sort(
const std::vector<PresetSchema>& presets,
const SortOptions& options);
// Pagination
std::vector<PresetSchema> paginate(
const std::vector<PresetSchema>& presets,
size_t page_size,
size_t page_number);
// Saved filters
void saveFilter(const std::string& name, const PresetFilter& filter);
PresetFilter loadFilter(const std::string& name);
std::vector<std::string> getSavedFilters();
};
struct PresetFilter {
std::vector<std::string> categories;
std::vector<ModuleType> module_types;
std::optional<PresetSchema::Version> min_version;
std::optional<PresetSchema::Version> max_version;
std::optional<float> min_rating;
std::optional<float> max_rating;
std::vector<std::string> authors;
std::vector<std::string> tags_any;
std::vector<std::string> tags_all;
std::optional<bool> has_resources;
std::optional<bool> is_favorite;
// Custom predicate
std::function<bool(const PresetSchema&)> custom;
};
enum class SortField {
Name, DateCreated, DateModified, Rating,
UsageCount, Category, Author, Relevance, Random
};
enum class SortOrder { Ascending, Descending };
Usage Examples¶
Example 1: Basic Search¶
#include <preset_browser.hpp>
// Create database and load presets
PresetDatabase db;
db.loadFromDirectory("factory_presets/");
// Create search engine
SearchEngine search;
search.indexPresets(db.getAllPresets());
// Simple search
auto results = search.search("warm pad");
std::cout << "Found " << results.size() << " results:\n";
for (const auto& result : results) {
std::cout << " " << result.preset.header.name
<< " (score: " << result.score << ")\n";
}
Example 2: Advanced Filtering¶
// Create filter for specific needs
PresetFilter filter;
filter.categories = {"Bass", "Sub Bass"};
filter.module_types = {ModuleType::L1_Atom};
filter.min_rating = 4.0f;
filter.tags_all = {"analog"}; // Must have "analog" tag
filter.has_resources = false; // No external samples
// Apply filter
FilterSystem filter_system;
auto filtered = filter_system.applyFilter(db.getAllPresets(), filter);
// Sort by rating
SortOptions sort;
sort.field = SortField::Rating;
sort.order = SortOrder::Descending;
auto sorted = filter_system.sort(filtered, sort);
// Show top 10
for (size_t i = 0; i < std::min(size_t(10), sorted.size()); ++i) {
std::cout << (i + 1) << ". " << sorted[i].header.name << "\n";
}
Example 3: Favorites and Recent¶
PresetDatabase db;
db.loadFromDirectory("all_presets/");
// Mark preset as used
db.markAsUsed("preset_bass_001");
// Add to favorites
db.addToFavorites("preset_bass_001");
// Get recent presets
auto recent = db.getRecentPresets(10);
std::cout << "Recent presets:\n";
for (const auto& preset : recent) {
std::cout << " " << preset.header.name << "\n";
}
// Get favorites
auto favorites = db.getFavorites();
std::cout << "\nFavorites (" << favorites.size() << "):\n";
for (const auto& preset : favorites) {
std::cout << " " << preset.header.name << "\n";
}
// Get popular presets
auto popular = db.getPopularPresets(20);
std::cout << "\nMost popular:\n";
for (size_t i = 0; i < std::min(size_t(5), popular.size()); ++i) {
std::cout << (i + 1) << ". " << popular[i].header.name << "\n";
}
Example 4: Tag-Based Search¶
SearchEngine search;
search.indexPresets(all_presets);
// Find presets with specific tags
SearchQuery query;
query.tags_all = {"synth", "warm"}; // Must have both
query.tags_any = {"pad", "lead"}; // Plus either pad or lead
query.fuzzy_match = true;
auto results = search.search(query);
// Group by category
std::map<std::string, std::vector<SearchResult>> by_category;
for (const auto& result : results) {
by_category[result.preset.header.category].push_back(result);
}
for (const auto& [category, presets] : by_category) {
std::cout << category << " (" << presets.size() << "):\n";
for (const auto& preset : presets) {
std::cout << " - " << preset.preset.header.name << "\n";
}
}
Performance Targets¶
| Operation | Target | Notes |
|---|---|---|
| Simple search | <10ms | Up to 10K presets |
| Complex query | <50ms | Multiple filters |
| Index build | <1s | 10K presets |
| Incremental index | <1ms | Single preset |
| Filter operation | <5ms | 10K presets |
| Sort operation | <20ms | 1K results |
| Database load | <500ms | 10K presets (metadata only) |
Files¶
05_14_05_preset_browser/
├── include/
│ ├── search_engine.hpp
│ ├── indexing_system.hpp
│ ├── preset_database.hpp
│ ├── filter_system.hpp
│ └── preset_preview.hpp
├── src/
│ ├── search_engine.cpp
│ ├── indexing_system.cpp
│ ├── preset_database.cpp
│ ├── filter_system.cpp
│ └── preset_preview.cpp
├── tests/
│ ├── test_search_engine.cpp
│ ├── test_indexing.cpp
│ ├── test_database.cpp
│ └── test_filtering.cpp
├── examples/
│ ├── basic_search_example.cpp
│ ├── advanced_filtering_example.cpp
│ ├── favorites_example.cpp
│ └── browser_ui_example.cpp
├── CMakeLists.txt
└── README.md (this file)
Dependencies¶
- 05_14_00_preset_schemas - Preset definitions
- 05_14_01_serialization_engine - Loading presets
- 05_14_03_resource_management - Resource handling
- nlohmann/json - JSON handling
Integration Example¶
// Complete browser setup
class PresetBrowser {
public:
PresetBrowser(const std::string& preset_directory) {
// Load all presets
database_.loadFromDirectory(preset_directory);
// Build search index
search_engine_.indexPresets(database_.getAllPresets());
std::cout << "Loaded " << database_.getPresetCount()
<< " presets\n";
}
// Search with text + filters
std::vector<PresetSchema> find(
const std::string& text,
const PresetFilter& filter) {
// Text search first
SearchQuery query;
query.text = text;
query.categories = filter.categories;
query.tags_all = filter.tags_all;
auto results = search_engine_.search(query);
// Extract presets
std::vector<PresetSchema> presets;
for (const auto& result : results) {
presets.push_back(result.preset);
}
// Apply additional filters
return filter_system_.applyFilter(presets, filter);
}
PresetDatabase& getDatabase() { return database_; }
private:
PresetDatabase database_;
SearchEngine search_engine_;
FilterSystem filter_system_;
};
Best Practices¶
- Index Incrementally - Update index as presets are added/removed
- Cache Search Results - Common queries can be cached
- Lazy Load Full Presets - Load metadata first, full preset on demand
- Use Pagination - Don't return thousands of results at once
- Save User Preferences - Remember filters, sorts, favorites
- Background Indexing - Index large collections in background thread
- Periodic Optimization - Rebuild index periodically for performance
Future Enhancements¶
- Machine Learning - Smart recommendations based on usage
- Similarity Search - "Find presets similar to this one"
- Cloud Sync - Sync favorites and recent across devices
- Collaborative Filtering - "Users who liked X also liked Y"
- Advanced Analytics - Usage patterns, trending presets
- Custom Tags - User-defined tags and categorization