StreamingDenoiserFactory.java

package com.morphiqlabs.wavelet.streaming;

import com.morphiqlabs.wavelet.api.Factory;
import com.morphiqlabs.wavelet.api.FactoryRegistry;
import com.morphiqlabs.wavelet.exception.InvalidArgumentException;
import com.morphiqlabs.wavelet.exception.ErrorContext;

/**
 * Factory for creating streaming wavelet denoisers.
 * 
 * <p>This factory provides different implementations optimized for various
 * use cases:</p>
 * <ul>
 *   <li>FAST: Low-latency real-time processing</li>
 *   <li>QUALITY: Higher SNR improvement with moderate latency</li>
 * </ul>
 * 
 * <p>The factory automatically selects the best implementation based on
 * configuration when using the {@link #create(StreamingDenoiserConfig)} method.</p>
 */
public final class StreamingDenoiserFactory implements Factory<StreamingDenoiserStrategy, StreamingDenoiserConfig> {
    
    private static final StreamingDenoiserFactory INSTANCE = new StreamingDenoiserFactory();
    
    static {
        // Register with the central factory registry
        FactoryRegistry.getInstance().register(
            "streamingDenoiser", 
            INSTANCE
        );
    }
    
    /**
     * Available implementations.
     */
    public enum Implementation {
        /** Fast implementation for real-time processing */
        FAST,
        /** Quality implementation for better denoising */
        QUALITY
    }
    
    private StreamingDenoiserFactory() {
        // Singleton
    }
    
    /**
     * Gets the singleton factory instance.
     */
    public static StreamingDenoiserFactory getInstance() {
        return INSTANCE;
    }
    
    @Override
    public StreamingDenoiserStrategy create() {
        // Create with default audio configuration
        return create(StreamingDenoiserConfig.defaultAudioConfig());
    }
    
    /**
     * Creates a streaming denoiser with explicit implementation selection.
     * 
     * @param implementation desired implementation
     * @param config configuration
     * @return configured denoiser
     */
    public static StreamingDenoiserStrategy create(Implementation implementation, StreamingDenoiserConfig config) {
        if (implementation == null) {
            throw new InvalidArgumentException(
                ErrorContext.builder("Implementation cannot be null")
                    .withContext("field", "implementation")
                    .withContext("value", "null")
                    .withContext("constraint", "non-null")
                    .withSuggestion("Use Implementation.FAST or QUALITY")
                    .build()
            );
        }
        
        return switch (implementation) {
            case FAST -> new FastStreamingDenoiser(config);
            case QUALITY -> new QualityStreamingDenoiser(config);
        };
    }
    
    @Override
    public StreamingDenoiserStrategy create(StreamingDenoiserConfig config) {
        if (config == null) {
            throw new InvalidArgumentException(
                ErrorContext.builder("Configuration cannot be null")
                    .withContext("field", "config")
                    .withContext("value", "null")
                    .withContext("constraint", "non-null")
                    .withSuggestion("Create config with StreamingDenoiserConfig.Builder")
                    .build()
            );
        }
        
        // Auto-select implementation based on configuration
        if (shouldUseFastImplementation(config)) {
            return new FastStreamingDenoiser(config);
        } else {
            return new QualityStreamingDenoiser(config);
        }
    }
    
    @Override
    public boolean isValidConfiguration(StreamingDenoiserConfig config) {
        if (config == null) return false;
        
        try {
            // Validate by attempting to determine implementation
            shouldUseFastImplementation(config);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    @Override
    public String getDescription() {
        return "Factory for creating streaming wavelet denoisers with FAST and QUALITY implementations";
    }
    
    /**
     * Determines whether to use the FAST or QUALITY implementation based on configuration.
     * <p>
     * Uses FAST implementation when:
     * <ul>
     *   <li>Block size ≤ 256 samples (low latency requirement), OR</li>
     *   <li>Overlap factor ≥ 0.5 AND adaptive threshold is enabled</li>
     * </ul>
     *
     * @param config the streaming denoiser configuration
     * @return {@code true} if the FAST implementation should be used; {@code false} for QUALITY
     */
    private boolean shouldUseFastImplementation(StreamingDenoiserConfig config) {
        // Use fast implementation for:
        // - Small block sizes (low latency requirement)
        // - High overlap with adaptive threshold (real-time adaptation)
        // - When explicitly optimizing for latency
        
        boolean smallBlock = config.getBlockSize() <= 256;
        boolean highOverlap = config.getOverlapFactor() >= 0.5;
        boolean adaptive = config.isAdaptiveThreshold();
        
        return smallBlock || (highOverlap && adaptive);
    }
}