Elephant rumble denoising workspace with a browser-first local web app.
The UI is now the primary interface. The backend roadmap still follows the same scientific shape: annotation-aware ingestion, low-frequency spectrogram design, separation, reconstruction, and evidence generation.
The repo contains the actual hackathon data assets:
audioFiles/: real source WAV recordingsspectrograms/: per-selection spectrogram imagesAudio Files Master (04_10_2026) - 20260324_rumbles_in_noise_for_hackathon.csv: canonical annotation spreadsheet exportaudio_files_master_extracted.txt: text extraction of the same master file for reference and debuggingpdf_extracted.txt: extracted text from the project-method PDF
Use the CSV as the canonical interval source. The extracted text files are reference material only.
For the short scientific rationale behind the denoising pipeline, see METHOD.md.
That note explains:
- why the STFT is tuned specifically for sub-30 Hz elephant rumble structure
- how annotation-guided per-recording NMF separates elephant energy from mechanical noise
- why Wiener-style soft masking is better than simple filtering or generic deep separators for this task
- where to find the current example outputs and proxy metrics
rumbleclean/ currently provides the ingestion layer:
- discovers
.wavrecordings - parses
.csv,.tsv, and.xlsxinterval sheets - recognizes the real master CSV columns:
Selection,Sound_file,Start_time,End_time,Call_type - returns joined recording bundles with
audio,sample_rate, andintervals - computes low-frequency spectrograms for both
directanddownsampledmodes - derives complementary noise-only time spans and spectrogram frame selections from the annotation intervals
webapp/ now provides the real browser workflow API:
GET /api/healthGET /api/heroesGET /api/heroes/<recording_id>POST /api/runs/heroes/<recording_id>POST /api/runs/uploadsGET /api/runs/<run_id>POST /api/uploads/inspectGET /artifacts/runs/<run_id>/<path:filename>
Hero presets and constrained uploads both end in the same manifest-backed run bundle under artifacts/runs/.
frontend/ is a React + Vite app and is now the real primary interface. The current app supports:
- a polished landing page
- a hero recordings browser
- a hero detail page that can run the backend pipeline
- a constrained upload flow for
.wav+.csv/.tsv/.xlsx - a manifest-backed results page with audio, plots, metrics, and clip links
.\.venv\Scripts\python -m pip install -r requirements.txtnpm --prefix frontend install.\.venv\Scripts\python -m webapp.appThis runs the local API on http://127.0.0.1:5000.
npm --prefix frontend run devThis starts the browser UI on http://127.0.0.1:5173. The Vite dev server proxies /api and /spectrograms to Flask.
- Open
http://127.0.0.1:5173 - Choose a hero preset or upload your own files
- The browser will run the pipeline and redirect to
/results/<run_id> - Each run writes its exported bundle under
artifacts/runs/<run_id>/
from rumbleclean import (
build_dataset,
compute_downsampled_spectrogram,
extract_noise_only_spectrogram,
load_recording_bundle,
)
dataset = build_dataset(
"audioFiles",
"Audio Files Master (04_10_2026) - 20260324_rumbles_in_noise_for_hackathon.csv",
)
bundle = dataset["04-040920-02_vehicle_1"]
audio, sample_rate, intervals = load_recording_bundle(
"audioFiles/04-040920-02_vehicle_1.wav",
"Audio Files Master (04_10_2026) - 20260324_rumbles_in_noise_for_hackathon.csv",
)
spectrogram = compute_downsampled_spectrogram(audio, sample_rate)
noise_only = extract_noise_only_spectrogram(
spectrogram,
intervals,
total_duration_seconds=len(audio) / sample_rate,
)load_recording_bundle() returns (audio, sample_rate, intervals) where:
audiois a NumPy array of normalized PCM samplessample_rateis the WAV sample rate as an integerintervalsis a tuple of typed annotation intervals sorted by start time- each interval may include a
selection_idwhen the source sheet provides one
Noise-only selection uses the complement of annotated call intervals and maps those spans onto spectrogram frame-center timestamps. That logic works for both spectrogram modes, which means later NMF training can consume the same interface whether the project is using the original-rate large FFT path or the faster downsampled path.
rumbleclean/separation.py adds the first semi-supervised NMF slice for Phase 3:
fit_noise_basis(...)learns a compact non-negativenoise_basisfrom noise-only spectrogram columnssemi_supervised_nmf(...)keeps thatnoise_basisfixed while learning:elephant_basisnoise_activationelephant_activation
- the result exposes separate
noise_componentandelephant_componentmagnitude estimates plus the combined reconstruction - the browser pipeline now passes the spectrogram frequency axis into a rumble-aware weighting path so the
~10-35 Hzband is less likely to be over-explained by the noise model
This means the pipeline does not need clean elephant-only training examples. Later Issue 3.4 can consume those separated magnitude components to build soft masks and reconstruct audio with the mixture phase.
Phase 4.1 formalizes the reconstruction step on top of the Phase 3 mask:
reconstruct_elephant_signal(...)reuses the original mixture phase fromSpectrogramResult.complex_spectrogram- the helper applies the elephant ratio mask to the complex mixture STFT rather than estimating a new phase
- the returned
PhaseReconstructionResultincludes the reconstructed waveform, mask, masked complex spectrogram, and mode/config metadata
This works for both direct and downsampled spectrogram modes because inversion uses the stored spectrogram config. The reconstructed sample rate currently follows the analysis mode, which means downsampled reconstructions come back at the downsampled analysis rate until later export work decides how to upsample or package them.
Phase 4.3 adds a unified export contract for hero runs now and upload runs later:
export_run_artifacts(...)writes each run underartifacts/runs/<run_id>/manifest.jsonis the canonical entrypoint for the UI and download flows- the bundle includes:
audio/cleaned_full_track.wavmetrics.txtclips/*.wavfor per-call exportsplots/before_spectrogram.svgplots/after_spectrogram.svgplots/comparison_spectrogram.svgplots/baseline_reference.txt
Phase 5.2 adds a compact proxy-metric report to each run bundle:
Noise suppression (dB)compares0-60 Hzenergy outside annotated calls before vs after separationHarmonic alignment scorecompares the dominant10-40 Hzridge inside annotated calls before vs after separation
The manifest stores relative paths so the same bundle format works whether the source came from a hero preset or a future uploaded recording.
Run the Python test suites:
.\.venv\Scripts\python -m unittest tests.test_dataset tests.test_hero_files tests.test_spectrogram tests.test_noise_segments tests.test_noise_dictionary tests.test_separation tests.test_exports tests.test_metrics tests.test_webapp -vRun the frontend tests:
npm --prefix frontend test -- --runRun the frontend production build:
npm --prefix frontend run buildUse ROADMAP.md for phase tracking and issue-level progress.