This is a sound recording application built with React 19 and TypeScript. It is a learning exercise. Buyer beware.
This is, in many ways, a recreation of this dictaphone web application. It is a PWA that you can install on your device and use without an Internet connection.
I am a bit of a sound effects enthusiast. I have a small collection of sound effects and used to use a very nice Roland stereo recording device but it can sometimes be a burden to carry around. The feature I liked the most about it was its reliability. It was always ready to go and I could record a sound effect in a matter of seconds. I wanted to create a similar experience for myself.
The main feature of this application will be reliability. Once installed, you tap it to open it and tap the record button to start recording immediately. My plan is to save the recording every second so that should the app crash or you accidentally close it, you will not lose your recording.
- Record audio from device microphone with real-time waveform visualization
- Quality presets: Voice (22.05kHz mono 64kbps), Music (44.1kHz stereo 128kbps), Hi-Fi (48kHz stereo 320kbps), and Custom
- Gain boost toggle (1x / 7x amplification)
- Reverb effect toggle
- Recording persists during tab navigation
- File size estimation based on selected quality settings
- Supports WebM/Opus (Chrome, Firefox, Edge) and MP4/AAC (Safari)
- Play, rename, and delete recordings
- Add descriptions and categories (Broad Sound Taxonomy)
- Recordings listed in reverse chronological order with quality badges and sync status indicators
- Share recordings via the Web Share API (converts to WAV for broad app compatibility)
- Includes recording name and app link in share text
canShare()pre-flight check with clear feedback on unsupported browsers
- OAuth2 authentication with Freesound
- Upload recordings to your Freesound account (auto-converts to WAV)
- Download sounds tagged
sound-recorder-syncfrom your account - Edit name/description on approved sounds and push changes to Freesound
- Track moderation status (Processing, In Moderation, Approved, Failed)
- Cross-device sync — recordings uploaded on one device appear on others
- Rate limit handling with automatic backoff and retry
- Install as a standalone app on any device
- Full offline support — record, edit, and manage without internet
- Background sync queues uploads for when connectivity returns
- Service worker with asset precaching for offline-first experience
- Online/offline status indicator
- Record — recording interface with visualizer
- Recordings — manage all local and synced recordings
- Settings — quality presets and advanced audio configuration
- User — Freesound account connection and profile info
You can see a live demo here of the current development version.
The app records in the browser's native format:
- WebM/Opus (
audio/webm;codecs="opus") - Chrome, Firefox, Edge - MP4/AAC (
audio/mp4) - Safari fallback
See src/hooks/useGetMediaRecorder.ts for implementation.
When syncing to Freesound, recordings are converted from WebM/Opus to WAV (16-bit PCM) before upload. See src/utils/audioConverter.ts.
Why WAV instead of uploading WebM directly?
- Freesound officially supports: WAV, FLAC, OGG, MP3, AIFF
- WebM is not officially listed as supported
- WAV is universally accepted and avoids potential compatibility issues
Trade-offs of WAV conversion:
- Larger file size (uncompressed PCM vs compressed Opus)
- Lossy conversion (Opus → PCM is a decode, not a transcode)
- More processing time on client
Future consideration: Freesound also accepts OGG, which uses the same Opus codec as WebM. A WebM → OGG conversion would be a lossless container change (same audio data, different wrapper). However, browsers don't provide a native API for this conversion. Libraries like FFmpeg.wasm could enable this but would add significant bundle size. For now, WAV conversion is simpler and guaranteed to work.
The app supports bidirectional sync with Freesound:
- Upload — local recordings are uploaded to your Freesound account
- Download — remote sounds tagged
sound-recorder-syncare downloaded to the app
Freesound sync uses OAuth 2.0. Because Freesound's OAuth flow requires a server-side token exchange, requests are proxied through a lightweight Cloudflare Worker.
| Variable | Description |
|---|---|
VITE_FREESOUND_CLIENT_ID |
Your Freesound API client ID |
VITE_FREESOUND_OAUTH_PROXY_URL |
URL of the OAuth proxy worker |
See .env.example for reference.
- React 19 with TypeScript
- Vite — build tool and dev server
- Vitest — test runner (340 tests)
- Workbox — service worker and offline caching (via vite-plugin-pwa)
- IndexedDB — local storage via
idblibrary - Web Share API — native sharing to other apps
- MediaRecorder API
- MediaStream Recording
- MediaDevices.getUserMedia()
- Vitest Documentation
- Vite Documentation
- MediaRecorder Pollyfill
- React Media Recorder
- use-media-recorder (React based hooks to utilize the MediaRecorder API for audio, video and screen recording)
Issues reported / uncovered / contributed to while working on this project.
- How to mock MediaRecorder API in Jest (project has since migrated to Vitest)
- How to mock a read-only property of a native browser object
- Bug 245056 Audio element displays Error when using Blob URL as src