Ribbit Radio

A WebAssembly-based digital radio communication application supporting real-time messaging over audio signals. Ribbit uses advanced DSP (Digital Signal Processing) algorithms to encode/decode messages into audio waveforms suitable for transmission via radio, speakers, or any audio medium.
Current Project Status
Version: 0.1.2 (Development)
Status: Production-ready core functionality with active development on advanced features
β
Completed Features
- WebAssembly Encoder/Decoder: High-performance C++ signal processing compiled to WASM (~103KB)
- Friendly WASM API: New
RibbitWASM class with promise-based interface for easy integration
- Dual-Mode Messaging:
- Chat Mode: UTF-8 free-form messaging (
Name|Callsign|Gridsquare&=Message)
- Contest Mode: Bitwise-packed structured format (40-60% smaller, includes timestamps)
- Real-time Audio Processing: 8kHz sample rate, continuous audio streaming for message detection
- Web Audio API Integration: Browser-based audio I/O with automatic context management
- IndexedDB Storage: Persistent message history with automatic restoration
- Service Worker: Offline support with caching
- PWA Support: Installable web app with manifest
- Visual Codec Tools: Interactive message encoding/decoding visualization
- Comprehensive Test Suite:
- Automated testing with multiple test scenarios
- Microphone Live Test: Real-time decoding from audio input
- WAV File Generator: Create audio files for cross-device and radio testing
- Cross-device validation and over-the-air testing
- GPS Integration: Automatic gridsquare calculation from coordinates
- Theme Support: Multiple color schemes (Ribbit Light, Ribbit Dark, World Radio League)
- Message Format Validation: Input sanitization, error handling, and duplicate detection
- Optimized Audio Processing: New
digestFeedOptimized() function with improved memory management, 50% fewer memory copies, and bounds checking (toggle in System Settings)
- Smart Decode Error Handling: Debounced error messages prevent UI spam from invalid signals
- Wake-up Tone: 300Hz preamble for radio VOX activation
π§ In Progress / Planned Features
- Enhanced message validation and error recovery
- ACK array implementation for contest mode
- Contest mode UI integration in main application
- Message acknowledgment tracking
- Statistics dashboard
- ADIF/Cabrillo logging export
- QSO mode for automatic contact logging
- Performance monitoring and profiling tools
Project Structure
.
βββ build.bat # Windows build script (auto-installs Emscripten)
βββ run_tests.bat # Windows test server launcher
βββ run_tests.sh # Linux/Mac test server launcher
βββ README.md # This file
βββ Docs/ # Comprehensive documentation
βββ Docs/ # Comprehensive documentation
β βββ codec.md # Codec & Message Architecture
β βββ quick_start.md # Quick Start Guide
β βββ ribbit_wasm.md # WASM Implementation Details
β βββ ...
βββ web/ # Web assets served to clients
β βββ index.html # Main application (v0.1.2)
β βββ messageCodec.html # Visual message encoder/decoder
β βββ headerCodec.html # Header field codec
β βββ wasm_tests.html # Test suite interface
β βββ decoder_tests.html # Live microphone testing & WAV generator
β βββ settings-page.html # Settings interface
β βββ ribbit.webmanifest # PWA manifest
β βββ sw.js # Service worker (offline support)
β βββ scripts/ # JavaScript modules
β β βββ ribbit.js # Emscripten WASM wrapper
β β βββ ribbit.wasm # Compiled WebAssembly binary (~103KB)
β β βββ ribbit-wasm.js # Friendly WASM API wrapper
β β βββ index.js # Main application logic
β β βββ message_format.js # Message format handler
β β βββ messageCodec.js # Message encoding/decoding API
β β βββ decoder_tests.js # Live testing implementation
β β βββ wasm_tests.js # Test suite
β β βββ wav.js # WAV file utilities
β β βββ ...
β βββ styles/ # CSS stylesheets
β βββ assets/ # Icons and images
β βββ test/ # Test files
β βββ test-e2e/ # End-to-end tests (Playwright)
β βββ setup.js # Test configuration
βββ src/ # C++ source code
βββ ribbit/
βββ src/
β βββ ribbit.cc # Main WASM bindings
β βββ message_format.cc # Message packing/unpacking
β βββ decode.cc # Decoder implementation
β βββ dsp/ # Digital Signal Processing library
β βββ encoder.hh # Signal encoder
β βββ decoder.hh # Signal decoder
β βββ polar_*.hh # Polar codes (error correction)
β βββ ... (60+ DSP headers)
βββ include/
βββ message_format.hh # Message format definitions
Building
Prerequisites
- Git
- Windows environment (for build.bat)
- C++17 compatible compiler
- Emscripten SDK 4.0.8 (automatically installed by build.bat)
Quick Build (Windows)
- Open Command Prompt or PowerShell
- Navigate to the project directory
-
Run the build script:
The script will:
- Automatically download and set up Emscripten SDK if not present
- Compile the C++ code to WebAssembly
- Output the files to the
web directory:
ribbit.js - JavaScript glue code
ribbit.wasm - WebAssembly binary
Manual Emscripten Setup
If you prefer manual setup or are not using Windows, follow these steps:
-
Clone Emscripten SDK:
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
-
Install and activate latest version:
./emsdk install latest
./emsdk activate latest
-
Set up environment variables:
# On Windows (PowerShell)
.\emsdk_env.ps1
# On Windows (Command Prompt)
.\emsdk_env.bat
# On Linux/macOS
source ./emsdk_env.sh
-
Verify installation:
-
Manual compilation:
emcc src/ribbit/src/ribbit.cc src/ribbit/src/message_format.cc -o web/scripts/ribbit.js ^
-s WASM=1 ^
-s EXPORTED_RUNTIME_METHODS=['ccall','cwrap','stringToUTF8','UTF8ToString','lengthBytesUTF8'] ^
-s EXPORTED_FUNCTIONS=['_malloc','_free','_createEncoder','_destroyEncoder','_createDecoder','_destroyDecoder','_feed_pointer','_feed_length','_message_pointer','_message_length','_signal_pointer','_signal_length','_payload_pointer','_payload_length','_feedDecoder','_digestFeed','_initEncoder','_readEncoder','_pack_contest_message','_unpack_contest_message'] ^
-I src/ribbit/include ^
-std=c++17 ^
-O3 ^
-s ALLOW_MEMORY_GROWTH=1 ^
-s INITIAL_MEMORY=16MB ^
-s MAXIMUM_MEMORY=64MB ^
-s STACK_SIZE=1MB ^
-s MODULARIZE=1 ^
-s EXPORT_ES6=0 ^
-s ENVIRONMENT=web ^
-s FILESYSTEM=0 ^
-s ASSERTIONS=0 ^
-s MALLOC=emmalloc ^
-msimd128 ^
--closure 0 ^
-flto
Note: The build includes both ribbit.cc and message_format.cc to support dual-mode messaging. The EXPORTED_RUNTIME_METHODS includes string conversion functions required for message format handling.
Build Optimization Features
The build script uses the following optimizations:
- -O3: Maximum optimization level for performance
- -flto: Link-time optimization for better code generation
- -msimd128: SIMD (Single Instruction Multiple Data) support for parallel processing
- ALLOW_MEMORY_GROWTH=1: Dynamic memory allocation
- INITIAL_MEMORY=16MB: Starting memory allocation
- MAXIMUM_MEMORY=64MB: Maximum allowed memory
- STACK_SIZE=1MB: Stack size for function calls
- MODULARIZE=1: Creates a module for better integration
- ENVIRONMENT=web: Optimized for web browser environment
- FILESYSTEM=0: Disables filesystem support (not needed)
- ASSERTIONS=0: Removes runtime assertions for smaller size
- MALLOC=emmalloc: Lightweight malloc implementation
Setup and running locally
- Serve the app (WASM requires a real origin;
file:// will not work):
- Windows:
run_tests.bat
- Linux/Mac:
./run_tests.sh
- Or from repo root:
python3 -m http.server 8000 and open http://localhost:8000/web/ (HTTPS needed for microphone: use the scripts or https://localhost:8443 if configured).
-
Main app: web/index.html β chat, encode/decode, settings. Use Settings β Application β Install App to add to home screen for offline use.
- WASM and tests:
- Decoder and encoder:
- Message format and header codec:
Development
- Web assets are served from the
web directory
- C++ source code is in the
src/ribbit directory
- The WebAssembly build output goes to the
web/scripts directory
- Emscripten SDK is not included in git (see
.gitignore)
Developer-Friendly WASM API
Ribbit now includes a modern, promise-based WASM API that makes integration simple:
// Import the friendly API
import { RibbitWASM } from './scripts/ribbit-wasm.js';
// One-line initialization
const ribbit = await RibbitWASM.load();
// Encode a message
const audioBuffer = await ribbit.encodeMessage("Hello World!", {
callsign: "W1AW",
gridsquare: "FN31pr",
name: "John"
});
// Decode audio
const decoded = await ribbit.decodeAudio(audioBuffer);
console.log("Received:", decoded.text);
// Cleanup when done
ribbit.destroy();
Key Features:
- Automatic memory management (no manual malloc/free)
- Promise-based async API
- TypeScript definitions included
- Error handling built-in
- Simple encode/decode methods
See Docs/README_WASM_API.md for complete API documentation.
Testing
A comprehensive test suite is available to verify encoder/decoder functionality, including automated tests, live microphone testing, WAV file generation for cross-device validation, and end-to-end browser testing.
Quick Start
Windows:
Linux/Mac:
Then open your browser to:
- WASM Tests:
http://localhost:8000/web/wasm_tests.html
- Decoder Tests:
https://localhost:8443/decoder_tests.html (requires HTTPS server)
Test Features
Automated Testing:
- Manual encode/decode testing with custom messages
- Automated test suite with multiple test cases
- Stress testing with configurable iterations (1-1000 messages)
- Real-time result display with pass/fail indicators
- Noise simulation for robustness testing (0-100% noise levels)
- Performance benchmarking
Live Testing (decoder_tests.html):
- Microphone Live Test: Real-time decoding from audio input
- Test over-the-air signal reception from radio
- Cross-device testing (play on Device B, decode on Device A)
- Automatic message validation with duplicate detection
- Live message display with timestamps (last 20 messages)
- Smart debouncing (2-second window prevents duplicates)
- WAV File Generator: Create audio files for testing
- Includes 300Hz wake-up tone for radio VOX activation
- Configurable message, callsign, and gridsquare
- Audio playback preview
- Automatic filename generation with timestamp
- Cross-device and radio transmission testing
- Standard format: 8kHz, 16-bit mono PCM WAV
End-to-End Testing:
- Playwright-based browser automation
- Cross-browser compatibility testing
- User workflow validation
- Performance monitoring
Documentation:
1. Visual Message Codec
URL: http://localhost:8000/web/messageCodec.html β
Interactive encoder/decoder that shows:
- Binary visualization (1s and 0s, color-coded by field)
- Hex encoding/decoding (copy/paste friendly)
- Mode comparison (see efficiency gains between Chat and Contest modes)
- Round-trip verification (encode β decode β verify)
- Field-by-field breakdown (callsign, timestamp, gridsquare, etc.)
URL: http://localhost:8000/web/message_format_demo.html πΈ
A complete end-to-end demo of the Ribbit message format using the actual WebAssembly binary.
- Verify Message IDs: See the unique 80-bit ID generated in real-time
- Test Contest Mode: Toggle between Chat (UTF-8) and Contest (Packed) modes
- Compare Efficiency: See exact byte savings (40-60% smaller in Contest mode)
- Live Encoding/Decoding: Test with your own messages
3. Decoder Tests & Live Testing
URL: https://localhost:8443/decoder_tests.html π€
Complete testing environment with:
- Automated Tests: Run predefined test suites with noise simulation
- Microphone Live Test: Real-time decoding from audio input
- WAV File Generator: Create portable test files for cross-device testing
- Performance Metrics: Track success rates and decoding accuracy
[!NOTE]
All tools require a local HTTP server to run (due to WASM security restrictions).
Run: python3 -m http.server 8000 or use the provided test scripts.
Ribbit now supports dual-mode messaging:
Chat Mode (Type 1) π¬
- Current UTF-8 format:
"Name|Callsign|Gridsquare&=Message"
- Simple, flexible, any UTF-8 characters
- Best for casual conversations
Contest Mode (Type 2) π
- Bitwise-packed efficient format
- 40-60% smaller than chat mode
- Includes UTC timestamp (31 bits, 2-sec resolution, auto-updated)
- Timestamp visualization - See Year/Month, Day, Hour, Minute, Second bits
- Unique Message ID (80-bit Hex) - Callsign + Timestamp + Emergency flag for deduplication
- Room for ACK arrays (20+ ACKs possible)
- Best for contests, structured communications
- ACK/QSO ready - Callsign + timestamp for contact confirmation
Example Savings: βHello from Ribbit!β is 37% smaller in Contest mode (52 β 33 bytes)
Full Details: Docs/ribbit_wasm.md
Known Issues & Bugs
π Confirmed Bugs
- Service Worker Cache Versioning
- Location:
web/sw.js
- Issue: Cache version
'ribbit-cache-v1' is hardcoded and may not invalidate old caches
- Impact: Users may see stale versions after updates
- Status: Should implement cache versioning strategy
- Severity: Low (affects updates)
- Audio Context State Management
- Location:
web/scripts/index.js - RibbitApp class
- Issue: Audio context suspension/resumption could be more robust
- Impact: Occasional audio playback issues on mobile browsers
- Status: Improved with user interaction handlers, but edge cases may exist
- Severity: Low (rare edge cases)
β οΈ Potential Issues
- Audio Buffer Size Mismatch
- Web Audio API provides power-of-2 buffer sizes (e.g., 2048), decoder expects 160-sample chunks
- Current implementation handles this with overflow buffer in
digestFeedOptimized()
- Recommendation: Add unit tests for various buffer sizes
- Concurrent Encode/Decode
- No explicit locking mechanism if encoder and decoder run simultaneously
- Current implementation suspends listening during transmission
- Recommendation: Add state checks or queue system for edge cases
- Large Message Handling
- Messages near 256-byte limit may not be validated early enough
- Recommendation: Add pre-encoding length validation
- IndexedDB Error Handling
- Some edge cases in database initialization may not be fully handled
- Recommendation: Add more comprehensive error recovery
Optimization Opportunities
- Web Workers for Audio Processing (High Priority)
- Move audio processing to Web Worker to prevent UI blocking
- Expected Impact: Smoother UI, better real-time performance
- Complexity: Medium
- Files to Modify:
web/scripts/index.js, create web/scripts/audio-worker.js
- Lazy WASM Loading (Medium Priority)
- Load WASM module only when needed, not on page load
- Expected Impact: Faster initial page load, reduced memory usage
- Complexity: Low
- Files to Modify:
web/scripts/index.js
- Note: Already partially implemented with
RibbitWASM.load()
- Message Queuing/Batching (Medium Priority)
- Queue multiple messages for batch processing
- Expected Impact: Better throughput for rapid message sending
- Complexity: Medium
- Files to Modify:
web/scripts/index.js, web/scripts/messages.js
- Optimize Bit Manipulation (Low Priority)
- Current bit manipulation in
message_format.cc uses loops
- Could use SIMD operations or lookup tables for common operations
- Expected Impact: 10-20% faster encoding/decoding
- Complexity: High
- Files to Modify:
src/ribbit/src/message_format.cc
- Memory Pooling (Low Priority)
- Reuse buffers instead of allocating/deallocating for each message
- Expected Impact: Reduced GC pressure, faster message processing
- Complexity: Medium
- Files to Modify:
web/scripts/ribbit-wasm.js, src/ribbit/src/ribbit.cc
- Note: Partially implemented in
digestFeedOptimized()
πΎ Memory Optimizations
- Reduce Static Buffer Sizes (If possible)
- Current buffers: FEED_LENGTH=2048, SIGNAL_LENGTH=16384, PAYLOAD_LENGTH=256
- Evaluate if sizes can be reduced without affecting functionality
- Expected Impact: Lower memory footprint
- Complexity: Medium (requires performance testing)
- Cleanup Unused WASM Memory
- Explicitly free temporary buffers after use
- Expected Impact: Lower peak memory usage
- Complexity: Low
- Files to Modify:
web/scripts/ribbit-wasm.js
- Status: Already implemented in
RibbitWASM class
π¦ Bundle Size Optimizations
- WASM Size Reduction
- Current WASM: ~103KB
- Investigate removing unused DSP functions if not needed
- Expected Impact: Smaller download, faster loading
- Complexity: High (requires careful dependency analysis)
- Code Splitting
- Separate contest mode codec into separate module
- Expected Impact: Faster initial load if contest mode not needed
- Complexity: Medium
π§ Code Quality Improvements
- TypeScript Migration (Long-term)
- Add type safety to JavaScript codebase
- Expected Impact: Fewer runtime errors, better IDE support
- Complexity: High
- Note: TypeScript definitions already exist for WASM API (
ribbit-wasm.d.ts)
- Unit Test Coverage
- Increase test coverage beyond integration tests
- Add tests for edge cases, error conditions
- Expected Impact: Higher code reliability
- Complexity: Medium
- Status: Test infrastructure in place with Jest and Playwright
- Error Recovery
- Add automatic retry for failed decode operations
- Expected Impact: Better resilience to noisy signals
- Complexity: Medium
- Status: Smart debouncing already implemented
Next Steps & Roadmap
- Enhanced Error Handling
- Improve decode error messages with more context
- Add retry logic for transient failures
- Better validation feedback in UI
- Contest Mode UI Integration
- Add mode selector to main application
- Integrate contest mode encoding/decoding in
index.js
- Add UI for contest mode message fields (timestamp, flags, etc.)
- Performance Monitoring
- Add real-time performance metrics display
- Track encoding/decoding times
- Monitor memory usage patterns
Short-term (Next Month)
- ACK Array Implementation
- Design ACK array structure (room for 20+ ACKs)
- Implement packing/unpacking logic
- Add UI for ACK management
- Statistics Dashboard
- Message counts, success rates
- Encoding/decoding performance metrics
- Bandwidth usage statistics
- Signal quality indicators
- Web Workers for Audio
- Offload audio processing to Web Worker
- Improve UI responsiveness
- Better handling of concurrent operations
- Enhanced Testing
- Expand E2E test coverage
- Add performance regression tests
- Cross-browser automated testing
Long-term (Next Quarter)
- ADIF/Cabrillo Logging
- Export contact logs in standard formats
- Import from existing log files
- Integration with popular logging software
- QSO Mode
- Automatic contact logging
- Duplicate detection
- Contest logging features
- Real-time QSO tracking
- Performance Monitoring
- Real-time performance metrics
- Bottleneck identification
- Performance profiling tools
- Automated performance testing
- Advanced Features
- Message compression
- Multiple modulation schemes
- Adaptive data rates
- Optional encryption layer
Saving and exporting contacts:
- ADIF logging support - Standard Amateur Data Interchange Format
- Cabrillo logging support - Contest logging format
- CSV export - For spreadsheet compatibility
- Integration - Direct export to popular logging software
AI Agent & Developer Guidance
This project has specific constraints to ensure offline reliability and portability. Please read the AgentGuidance before writing code.
Contributing
When reporting bugs or implementing optimizations:
- Bug Reports: Include reproduction steps, expected vs actual behavior, browser/OS info
- Optimizations: Include performance benchmarks before/after, explain trade-offs
- Code Changes: Follow existing code style, add tests for new features
- Documentation: Update relevant docs when adding features
Resources & Documentation
Deployment (GitHub Pages)
This repo is set up as a GitHub Pages site (e.g. https://<user>.github.io/badkangaroo.github.io/ or your custom domain). A GitHub Action deploys the web folder when you push to the release branch or when you push a release tag (e.g. v0.1.2).
- Branch: Push to
release to update the live site from the current web/ contents.
- Tag: Create and push a tag (e.g.
git tag v0.1.2 && git push origin v0.1.2) to trigger a deploy and record a specific version.
- Configure Settings β Pages to use the GitHub Action (or the
gh-pages branch if the workflow publishes there). See .github/workflows/deploy.yml for the workflow.