Skip to content

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

#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";
}
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

  1. Index Incrementally - Update index as presets are added/removed
  2. Cache Search Results - Common queries can be cached
  3. Lazy Load Full Presets - Load metadata first, full preset on demand
  4. Use Pagination - Don't return thousands of results at once
  5. Save User Preferences - Remember filters, sorts, favorites
  6. Background Indexing - Index large collections in background thread
  7. 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