Package Exports
- murmuraba
- murmuraba/package.json
Readme
Murmuraba π
Real-time audio noise reduction for web applications with advanced chunked processing.
Features β¨
- π― Real-time noise reduction using RNNoise neural network
- π¦ Chunked processing for streaming applications
- βΈοΈ Full stream control - pause, resume, stop
- π Real-time metrics with callbacks
- π§Ή Automatic cleanup after inactivity
- π§ Configurable logging and noise reduction levels
- πΎ Low memory footprint with WebAssembly
- ποΈ Advanced configuration options
- π Zero dependencies (except for RNNoise WASM)
What's New in v1.4.1 π
π₯ Professional UI Components with Brutal TDD
Complete production-ready React components with uncompromising quality standards:
AudioPlayer Component
- π΅ Professional Audio Player: Full-featured audio playback with clean architecture
- βΏ Complete Accessibility: ARIA labels, keyboard navigation, screen reader support
- ποΈ Advanced Controls: Play/pause, seeking, volume, time display, progress bar
- β‘ Performance Optimized: useMemo, useCallback, debouncing, memory leak prevention
- π‘οΈ Bulletproof Error Handling: Safe audio loading, format validation, graceful fallbacks
- β 23/23 TDD Tests Passing: Comprehensive test coverage with edge cases
- π¨ Zero Inline Styles: Clean CSS architecture ready for customization
AdvancedMetricsPanel Component
- π Engine Diagnostics Panel: Real-time system performance monitoring
- π¬ Detailed Metrics: Memory usage, processing time, WASM status, browser compatibility
- π― Smart Performance Indicators: Visual feedback for system health (Good/Moderate/High)
- βΏ Modal Accessibility: Proper dialog, keyboard navigation, escape handling
- ποΈ Component Composition: Modular architecture with MetricItem, PerformanceIndicator
- β 31/31 TDD Tests Passing: Complete test coverage including edge cases
- π¨ Professional Design: Clean layout with proper spacing and hierarchy
Clean Architecture Philosophy
- ποΈ Component Composition: Small, focused components with single responsibilities
- π TypeScript Strictness: No 'as any', complete type safety, proper interfaces
- π§ͺ Test-Driven Development: Write tests first, then implement features
- βΏ Accessibility First: WCAG compliance, keyboard navigation, screen reader support
- β‘ Performance Optimized: React best practices, memoization, efficient re-renders
- π‘οΈ Error Boundaries: Graceful handling of all edge cases and unexpected inputs
Complete Package Features
Core Engine
- π― Real-time Noise Reduction: RNNoise neural network with WebAssembly
- π¦ Advanced Chunked Processing: Configurable chunk sizes with streaming support
- π Full Stream Control: Start, pause, resume, stop with state management
- π Real-time Metrics: Continuous performance monitoring and callbacks
- π§Ή Automatic Cleanup: Memory management and resource disposal
- π§ Configurable Options: Noise reduction levels, logging, custom settings
React Integration
- πͺ useMurmubaraEngine Hook: Complete audio recording and processing solution
- π΅ Built-in Audio Playback: Toggle between original and processed audio
- π State Management: Recording time, chunks, status, and metrics
- β‘ Utility Functions: formatTime(), getAverageNoiseReduction(), and more
- ποΈ Zero-Setup Recording: MediaRecorder, streams, and chunking handled internally
Professional Components (NEW!)
- AudioPlayer: Production-ready audio playback component
- AdvancedMetricsPanel: System diagnostics and performance monitoring
- 100% Test Coverage: Both components have comprehensive TDD test suites
- Accessibility Compliant: Full WCAG support with keyboard navigation
- TypeScript Complete: Strict types, proper interfaces, zero any types
Architecture Highlights
- ποΈ Clean Separation: UI components separate from business logic
- π¦ Zero External Dependencies: Complete standalone solution
- π Type Safety: Full TypeScript support with strict configuration
- π§ͺ Test-Driven: Comprehensive test coverage with edge case handling
- βΏ Accessibility: WCAG 2.1 compliant components with keyboard support
- β‘ Performance: Optimized for production with best practices
Installation
npm install murmuraba
# or
yarn add murmuraba
# or
pnpm add murmurabaQuick Start
import { initializeAudioEngine, processStream } from 'murmuraba';
// Initialize the engine
await initializeAudioEngine({
logLevel: 'info',
noiseReductionLevel: 'high'
});
// Get user's microphone
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
// Process the stream
const controller = await processStream(stream);
// Use the processed stream
const processedStream = controller.stream;
// Control the stream
controller.pause(); // Pause processing
controller.resume(); // Resume processing
controller.stop(); // Stop and cleanupReact Hook Usage - Complete Example
The useMurmubaraEngine hook is now a complete audio processing solution that handles everything internally:
import { useMurmubaraEngine } from 'murmuraba';
function AudioComponent() {
const {
// Engine State
isInitialized,
isLoading,
error,
engineState,
metrics,
diagnostics,
// Recording State (complete state object)
recordingState, // { isRecording, isPaused, recordingTime, chunks }
currentStream, // Current MediaStream being processed
// Engine Control
initialize,
destroy,
// Recording Pipeline (all-in-one functions)
startRecording, // (chunkDuration?) => Promise<void> - handles everything
stopRecording, // () => void - stops and finalizes
pauseRecording, // () => void - pauses current recording
resumeRecording, // () => void - resumes paused recording
clearRecordings, // () => void - clears all chunks and URLs
// Audio Playback (built-in)
toggleChunkPlayback, // (chunkId, audioType) => Promise<void>
toggleChunkExpansion,// (chunkId) => void
// Utility Functions (included)
formatTime, // (seconds) => "MM:SS" format
getAverageNoiseReduction, // () => number (average across all chunks)
resetError // () => void - clears error state
} = useMurmubaraEngine({
autoInitialize: false, // Initialize on mount
defaultChunkDuration: 8, // Default chunk size in seconds
noiseReductionLevel: 'high', // Processing quality
bufferSize: 2048, // Audio buffer size
logLevel: 'info' // Logging level
});
return (
<div>
{/* Engine Initialization */}
{!isInitialized && !isLoading && (
<button onClick={initialize}>
Initialize Engine
</button>
)}
{isLoading && <div>π Initializing Neural Engine...</div>}
{/* Zero-Setup Recording - Just One Function Call */}
{isInitialized && (
<div>
{!recordingState.isRecording ? (
<button onClick={() => startRecording(8)}>
ποΈ Start Recording (8s chunks)
</button>
) : (
<>
<button onClick={stopRecording}>βΉοΈ Stop</button>
{recordingState.isPaused ? (
<button onClick={resumeRecording}>βΆοΈ Resume</button>
) : (
<button onClick={pauseRecording}>βΈοΈ Pause</button>
)}
<span>π΅ Recording: {formatTime(recordingState.recordingTime)}</span>
</>
)}
</div>
)}
{/* Real-time Processing Metrics */}
{metrics && recordingState.isRecording && (
<div>
<p>π Noise Reduction: {metrics.noiseReductionLevel.toFixed(1)}%</p>
<p>β‘ Latency: {metrics.processingLatency.toFixed(2)}ms</p>
<p>π Input Level: {(metrics.inputLevel * 100).toFixed(0)}%</p>
<p>π Average Reduction: {getAverageNoiseReduction().toFixed(1)}%</p>
</div>
)}
{/* Automatically Processed Chunks with Built-in Playback */}
<div>
<h3>π΅ Processed Chunks ({recordingState.chunks.length})</h3>
{recordingState.chunks.map((chunk, index) => (
<div key={chunk.id}>
<h4>Chunk #{index + 1} - {formatTime(chunk.duration / 1000)}</h4>
<p>π Noise Removed: {chunk.noiseRemoved.toFixed(1)}%</p>
{/* Built-in Audio Playback Controls */}
<button
onClick={() => toggleChunkPlayback(chunk.id, 'original')}
disabled={!chunk.originalAudioUrl}
>
π {chunk.isPlaying ? 'Stop' : 'Play'} Original
</button>
<button
onClick={() => toggleChunkPlayback(chunk.id, 'processed')}
disabled={!chunk.processedAudioUrl}
>
π΅ {chunk.isPlaying ? 'Stop' : 'Play'} Enhanced
</button>
<button onClick={() => toggleChunkExpansion(chunk.id)}>
{chunk.isExpanded ? 'β² Hide' : 'βΌ Show'} Details
</button>
{/* Automatic Detail Expansion */}
{chunk.isExpanded && (
<div>
<p>π
Start: {new Date(chunk.startTime).toLocaleTimeString()}</p>
<p>π End: {new Date(chunk.endTime).toLocaleTimeString()}</p>
<p>β‘ Processing: {chunk.metrics.processingLatency.toFixed(2)}ms</p>
<p>ποΈ Frames: {chunk.metrics.frameCount}</p>
<p>π Input Level: {(chunk.metrics.inputLevel * 100).toFixed(1)}%</p>
<p>π Output Level: {(chunk.metrics.outputLevel * 100).toFixed(1)}%</p>
</div>
)}
</div>
))}
</div>
{/* One-Click Cleanup */}
{recordingState.chunks.length > 0 && (
<button onClick={clearRecordings}>
π§Ή Clear All Recordings
</button>
)}
{/* Error Handling */}
{error && (
<div>
β οΈ {error}
<button onClick={resetError}>β</button>
</div>
)}
</div>
);
}Configuration Options
useMurmubaraEngine Hook Options
interface UseMurmubaraEngineOptions {
// Engine Initialization
autoInitialize?: boolean; // Auto-initialize engine on mount (default: false)
// Recording Configuration
defaultChunkDuration?: number; // Default chunk duration in seconds (default: 8)
// Audio Processing
noiseReductionLevel?: 'low' | 'medium' | 'high'; // Processing quality (default: 'high')
bufferSize?: 256 | 512 | 1024 | 2048 | 4096; // Audio buffer size (default: 2048)
// Logging & Debugging
logLevel?: 'none' | 'error' | 'warn' | 'info' | 'debug'; // Logging level (default: 'info')
// Advanced Options
useWorker?: boolean; // Use Web Worker for processing (default: true)
autoCleanup?: boolean; // Auto-cleanup inactive resources (default: true)
cleanupDelay?: number; // Cleanup delay in ms (default: 5000)
}Hook Return Interface
interface UseMurmubaraEngineReturn {
// Engine State
isInitialized: boolean;
isLoading: boolean;
error: string | null;
engineState: 'uninitialized' | 'initializing' | 'ready' | 'processing' | 'error';
metrics: ProcessingMetrics | null;
diagnostics: DiagnosticInfo | null;
// Recording State (Complete State Object)
recordingState: {
isRecording: boolean;
isPaused: boolean;
recordingTime: number; // Total recording time in seconds
chunks: ProcessedChunk[]; // Array of processed audio chunks
};
currentStream: MediaStream | null; // Current audio stream being processed
// Engine Control
initialize: () => Promise<void>;
destroy: (force?: boolean) => Promise<void>;
resetError: () => void;
// Complete Recording Pipeline (All-in-One Functions)
startRecording: (chunkDuration?: number) => Promise<void>; // Handles MediaRecorder setup
stopRecording: () => void; // Stops and finalizes all chunks
pauseRecording: () => void; // Pauses current recording
resumeRecording: () => void; // Resumes paused recording
clearRecordings: () => void; // Clears all chunks and audio URLs
// Built-in Audio Playback
toggleChunkPlayback: (chunkId: string, audioType: 'original' | 'processed') => Promise<void>;
toggleChunkExpansion: (chunkId: string) => void;
// Utility Functions (Built-in)
formatTime: (seconds: number) => string; // Format seconds to "MM:SS"
getAverageNoiseReduction: () => number; // Calculate average across all chunks
}Chunked Processing
Process audio in chunks for better control and metrics:
const controller = await processStreamChunked(stream, {
chunkDuration: 4000, // 4 seconds per chunk
onChunkProcessed: (chunk) => {
console.log({
duration: chunk.duration,
noiseRemoved: chunk.noiseRemoved,
startTime: chunk.startTime,
endTime: chunk.endTime,
metrics: chunk.metrics
});
}
});Professional UI Components π¨
AudioPlayer Component
A production-ready audio player with full accessibility and clean architecture:
import { AudioPlayer } from 'murmuraba';
function MyApp() {
const [audioSrc, setAudioSrc] = useState<string>();
const [isPlaying, setIsPlaying] = useState(false);
return (
<AudioPlayer
src={audioSrc}
label="Processed Audio"
onPlayStateChange={setIsPlaying}
volume={0.8}
muted={false}
disabled={false}
className="custom-player"
aria-label="Custom audio player for noise-reduced content"
/>
);
}AudioPlayer Features:
- ποΈ Full Controls: Play, pause, seek, volume, time display
- βΏ Accessibility: ARIA labels, keyboard navigation, screen reader support
- π¨ Customizable: CSS classes, custom styling, responsive design
- π‘οΈ Error Handling: Graceful loading failures, format validation
- β‘ Performance: Optimized re-renders, memory leak prevention
- π΅ Audio Support: All modern audio formats with fallbacks
AudioPlayer Props:
interface AudioPlayerProps {
src?: string; // Audio source URL
onPlayStateChange?: (isPlaying: boolean) => void; // Play state callback
className?: string; // Custom CSS classes
label: string; // Accessible label (required)
forceStop?: boolean; // Force stop playback
'aria-label'?: string; // Custom ARIA label
disabled?: boolean; // Disable player
volume?: number; // Volume (0-1)
muted?: boolean; // Muted state
}AdvancedMetricsPanel Component
A comprehensive diagnostics panel for monitoring engine performance:
import { AdvancedMetricsPanel } from 'murmuraba';
function DiagnosticsView() {
const { diagnostics } = useMurmubaraEngine();
const [showPanel, setShowPanel] = useState(false);
return (
<>
<button onClick={() => setShowPanel(true)}>
Show Engine Diagnostics
</button>
<AdvancedMetricsPanel
isVisible={showPanel}
diagnostics={diagnostics}
onClose={() => setShowPanel(false)}
className="my-diagnostics"
aria-label="Engine performance diagnostics panel"
/>
</>
);
}AdvancedMetricsPanel Features:
- π Real-time Metrics: Memory usage, processing time, active processors
- π¬ System Health: WASM status, browser compatibility, engine state
- π― Performance Indicators: Visual feedback (Good/Moderate/High usage)
- βΏ Modal Accessibility: Proper dialog with keyboard navigation
- π¨ Professional Design: Clean layout with proper information hierarchy
- β¨οΈ Keyboard Support: Escape to close, enter/space for buttons
AdvancedMetricsPanel Props:
interface AdvancedMetricsPanelProps {
isVisible: boolean; // Panel visibility
diagnostics: DiagnosticInfo | null; // Engine diagnostics data
onClose: () => void; // Close callback (required)
className?: string; // Custom CSS classes
'aria-label'?: string; // Custom ARIA label for dialog
}Diagnostic Information Structure:
interface DiagnosticInfo {
engineVersion: string; // Package version
wasmLoaded: boolean; // WebAssembly status
activeProcessors: number; // Number of active audio processors
memoryUsage: number; // Memory usage in bytes
processingTime: number; // Last processing time in milliseconds
engineState: string; // Current engine state
browserInfo?: { // Browser compatibility info
name?: string; // Browser name
audioAPIsSupported: boolean; // Audio API support status
};
}Integration Example:
import { useMurmubaraEngine, AudioPlayer, AdvancedMetricsPanel } from 'murmuraba';
function CompleteAudioApp() {
const {
// Engine and recording state
recordingState,
diagnostics,
startRecording,
stopRecording,
// Audio chunks for playback
getChunkUrl,
getProcessedChunkUrl
} = useMurmubaraEngine();
const [showDiagnostics, setShowDiagnostics] = useState(false);
const [selectedChunk, setSelectedChunk] = useState<number>(0);
return (
<div className="audio-app">
{/* Recording Controls */}
<button onClick={startRecording} disabled={recordingState.isRecording}>
Start Recording
</button>
<button onClick={stopRecording} disabled={!recordingState.isRecording}>
Stop Recording
</button>
{/* Audio Players for A/B Comparison */}
<div className="audio-comparison">
<AudioPlayer
src={getChunkUrl(selectedChunk)}
label="Original Audio"
className="original-player"
/>
<AudioPlayer
src={getProcessedChunkUrl(selectedChunk)}
label="Noise Reduced"
className="processed-player"
/>
</div>
{/* Diagnostics */}
<button onClick={() => setShowDiagnostics(true)}>
Engine Diagnostics
</button>
<AdvancedMetricsPanel
isVisible={showDiagnostics}
diagnostics={diagnostics}
onClose={() => setShowDiagnostics(false)}
/>
</div>
);
}API Reference
Core Functions
initializeAudioEngine(config?: MurmubaraConfig): Promise<void>
Initialize the global audio engine instance.
processStream(stream: MediaStream): Promise<StreamController>
Process a MediaStream with noise reduction.
processStreamChunked(stream: MediaStream, config: ChunkConfig): Promise<StreamController>
Process a MediaStream in chunks with callbacks.
destroyEngine(options?: { force?: boolean }): Promise<void>
Destroy the engine and cleanup all resources.
getEngineStatus(): EngineState
Get the current engine state.
getDiagnostics(): DiagnosticInfo
Get detailed diagnostics information.
StreamController
interface StreamController {
stream: MediaStream; // Processed audio stream
stop(): void; // Stop processing
pause(): void; // Pause processing
resume(): void; // Resume processing
getState(): EngineState; // Get current state
}Metrics
interface ProcessingMetrics {
noiseReductionLevel: number; // 0-100%
processingLatency: number; // milliseconds
inputLevel: number; // 0-1
outputLevel: number; // 0-1
timestamp: number;
frameCount: number;
droppedFrames: number;
}Browser Requirements
- Web Audio API support
- WebAssembly support
- Modern browser (Chrome 66+, Firefox 60+, Safari 11.1+, Edge 79+)
Testing
Unit Tests
npm test # Run all tests
npm run test:coverage # Run with coverage reportIntegration Tests (Browser)
For real-world audio testing with actual noise reduction, see our DOM Integration Testing Guide.
This guide covers:
- Testing with real microphone input
- File upload testing with noisy audio
- Performance benchmarking
- Visual waveform analysis
- SNR (Signal-to-Noise Ratio) measurements
Performance Tips
Use appropriate buffer sizes:
- Lower latency: 256 or 512
- Better performance: 2048 or 4096
Configure noise reduction level based on your needs:
low: Minimal processing, lowest latencymedium: Balanced (default)high: Maximum noise reduction
Enable auto-cleanup to free resources when inactive
Migration from v1.2.x to v1.3.0
Before v1.3.0 (Complex Setup)
// Multiple hooks and manual setup required
const { processStream, cleanup } = useAudioEngine();
const { startRecording, stopRecording } = useAudioRecorder();
const { convert } = useAudioConverter();
// Manual MediaRecorder setup
const mediaRecorder = new MediaRecorder(stream);
// Manual chunk handling
// Manual audio URL management
// Manual playback controls
cleanup(); // Partial cleanupAfter v1.3.0 (Zero Setup)
// Single hook with everything built-in
const {
startRecording, // Handles MediaRecorder, chunking, conversion
stopRecording, // Complete cleanup
toggleChunkPlayback, // Built-in playback
recordingState, // Complete state
formatTime, // Utility functions included
clearRecordings // One-click cleanup
} = useMurmubaraEngine();
// Just one function call - handles everything
await startRecording(8); // 8-second chunks, automatic WAV conversion, playback readyKey Improvements in v1.3.0
- π₯ 90% Less Code: Frontend reduced from 1700+ lines to <100 lines
- π¦ Complete Package: All logic moved to reusable package
- π― Zero Setup: No manual MediaRecorder or chunk management
- π WAV-First: Automatic format prioritization and conversion
- π§Ή Auto Cleanup: Proper memory management built-in
- π΅ Integrated Playback: No need for external audio components
License
MIT Β© Murmuraba Team
Contributing
Contributions are welcome! Please read our Contributing Guide for details.
Support
- π Report bugs
- π‘ Request features
- π Documentation