[ Installation ]

npx wally-ui add audio-waveform

[ Live Preview ]

[ Import ]

import { AudioWaveform } from './components/wally-ui/audio-waveform/audio-waveform';
import { AudioWaveformService } from './components/wally-ui/audio-waveform/audio-waveform.service';
@Component({
  selector: 'app-example',
  imports: [AudioWaveform],
  templateUrl: './example.html'
})

[ Basic Usage ]

Minimal Example

<wally-audio-waveform
  [isStartRecording]="isRecording()"
  [isStopRecording]="!isRecording()">
</wally-audio-waveform>

With Recording Timer

<wally-audio-waveform
  [isStartRecording]="isRecording()"
  [isStopRecording]="!isRecording()"
  [showTimer]="true">
</wally-audio-waveform>

Complete Example with Controls

<div class="flex flex-col gap-4">
  <!-- Waveform Visualizer -->
  <wally-audio-waveform
    [isStartRecording]="isRecording()"
    [isStopRecording]="!isRecording()"
    [showTimer]="true">
  </wally-audio-waveform>

  <!-- Recording Controls -->
  <div class="flex gap-2">
    @if (!isRecording()) {
      <button (click)="startRecording()"
        class="px-4 py-2 bg-red-500 text-white rounded-full">
        Start Recording
      </button>
    } @else {
      <button (click)="stopRecording()"
        class="px-4 py-2 bg-neutral-500 text-white rounded-full">
        Stop Recording
      </button>
    }
  </div>
</div>
export class RecordingComponent {
  isRecording = signal(false);

  startRecording() {
    this.isRecording.set(true);
  }

  stopRecording() {
    this.isRecording.set(false);
  }
}

[ Visual Examples ]

Without Timer

Basic waveform visualization without recording timer display.

With Timer

Waveform visualization with recording timer in MM:SS format.

With Download Functionality

Record audio and download the result as a WebM file.

[ Service Integration ]

Access the AudioWaveformService to download, retrieve, or clear recorded audio.

// Access the service to get recorded audio
export class RecordingComponent {
  @ViewChild(AudioWaveform) audioWaveform!: AudioWaveform;

  downloadRecording() {
    const service = this.audioWaveform.audioWaveformService;
    service.downloadRecording('my-recording.webm');
  }

  getRecordedBlob() {
    const service = this.audioWaveform.audioWaveformService;
    const blob = service.recordedAudioBlob();
    return blob;
  }

  clearRecording() {
    const service = this.audioWaveform.audioWaveformService;
    service.clearRecording();
  }
}

[ How It Works ]

The component uses the Web Audio API to analyze microphone input in real-time with FFT (Fast Fourier Transform) frequency analysis.

// How it works under the hood:
// 1. getUserMedia() - Request microphone access
// 2. AudioContext - Process audio in real-time
// 3. AnalyserNode - FFT analysis (256 samples → 128 frequencies)
// 4. getByteFrequencyData() - Get frequency values (0-255)
// 5. Normalize to 0-100% for bar heights
// 6. requestAnimationFrame - Smooth 60fps animation

Technical Flow

  1. Microphone Access: getUserMedia() requests permission
  2. Audio Context: Creates AudioContext for processing
  3. Frequency Analysis: AnalyserNode performs FFT (256 samples → 128 frequencies)
  4. Data Extraction: getByteFrequencyData() returns values 0-255
  5. Bar Grouping: Averages frequencies into 30/65 bars (responsive)
  6. Normalization: Converts to 0-100% for CSS heights
  7. Animation Loop: requestAnimationFrame updates at 60fps
  8. Recording: MediaRecorder saves audio as WebM Blob

[ Configuration ]

Service-level configuration (read-only constants for optimal performance).

FFT_SIZE = 256  // Higher = more frequency detail

FFT size for frequency analysis. Higher values provide more detail but use more CPU.

BAR_COUNT = 30 (mobile) | 65 (desktop)  // Auto-responsive

Automatically adjusts based on viewport width for optimal display.

SMOOTHING = 0.8  // 0 (no smoothing) to 1 (max smoothing)

Smoothing constant for animation. 0 = no smoothing (choppy), 1 = max smoothing (laggy).

[ Properties ]

PropertyTypeDefaultDescription
Input Properties
isStartRecordingInputSignal<boolean>falseSignal to start recording. Set to true to begin capturing audio
isStopRecordingInputSignal<boolean>falseSignal to stop recording. Set to true to stop capturing audio
showTimerInputSignal<boolean>falseControls visibility of recording timer (MM:SS format)
Service Signals (Read-Only)
isRecordingWritableSignal<boolean>-Current recording state (true = recording, false = stopped)
audioDataWritableSignal<number[]>-Array of normalized bar heights (0-100%) updated at 60fps
recordedAudioBlobWritableSignal<Blob | null>-Recorded audio as a Blob (audio/webm format). Available after stopping recording
recordedAudioUrlWritableSignal<string | null>-Temporary URL for recorded audio. Use for playback or download

[ Service Methods ]

Public methods available on AudioWaveformService for managing recorded audio.

downloadRecording(filename?: string): void

Downloads the recorded audio file. Optionally specify custom filename.

clearRecording(): void

Clears recorded audio and revokes URL to free memory. Call after download or discard.

[ Future Features ]

Audio Transcription (Coming Soon)

Automatic speech-to-text transcription will be added in a future release. The API preview below shows the planned implementation.

// COMING SOON: Audio Transcription
// The component will support automatic transcription in a future release

<wally-audio-waveform
  [isStartRecording]="isRecording()"
  [isStopRecording]="!isRecording()"
  [enableTranscription]="true"
  (transcriptionComplete)="onTranscription($event)">
</wally-audio-waveform>

[ Browser Support ]

// Requires modern browsers with:
// - Web Audio API
// - MediaStream API
// - MediaRecorder API
//
// Supported: Chrome 60+, Firefox 55+, Safari 14+, Edge 79+

[ Accessibility ]

The component follows accessibility best practices for audio recording interfaces.

<!-- The component includes built-in accessibility -->
<!-- Timer updates announced via aria-live region (when showTimer=true) -->
<!-- Waveform visualizer is decorative (aria-hidden) -->
  • Waveform Visualization: Decorative element (aria-hidden), not essential for understanding recording state
  • Recording Timer: Announced via ARIA live region when showTimer=true
  • Control Buttons: Use clear aria-label attributes (e.g., "Start audio recording")
  • Keyboard Support: All interactions keyboard-accessible via standard button controls