You have audio in your app and need variants: previews, downloads, waveforms, normalized versions. Five honest answers. The right one depends on where you are, and sometimes it is not this one.
| audioproxy | Pre-generate in your app | Cloudinary | Mux | Batch pipelineMediaConvert, Transloadit | |
|---|---|---|---|---|---|
| Variants on demand, nothing rendered in advance | Yes. First request renders and streams; every one after is a cache hit | No. Pre-rendering is the mechanism | Yes, via transformation URLs | Clipping of assets; audio is not the focus | No. Jobs run ahead of requests |
| Waveform data for player UIs | Yes. audiowaveform-compatible JSON or binary, cached like audio | You run audiowaveform yourself and store the output | Waveform images, not data | Not offered for audio | Another job to write |
| Loudness normalization | EBU R128, one URL option, per variant | Your ffmpeg flags, your job | Volume in percent or dB; no loudness target in the audio transformation reference | normalize_audio at asset creation, -24 LUFS. Fixed target, and not changeable afterwards | ITU-R BS.1770-1 to -4 with a target LKFS you choose |
| Speech cleanup | enhance:voice: high-pass, denoise, de-ess, compress, limit behind one option, cached like any variant | Your own chain to build and keep working | Via the Dolby.io Media Enhancement add-on: a support request plus a separate Dolby API key | Loudness normalization only | Transloadit exposes ffmpeg filters; MediaConvert does not offer speech enhancement |
| Your storage stays yours | Sources and variants live in your buckets or on your disk | Yes | Derived assets live with the vendor | Assets live with the vendor | Reads and writes your buckets |
| Time-boxed links | exp option, signed into the URL | Your framework's signed URLs | Expiring delivery tokens | Signed playback tokens | Storage-level presigning |
| Video | Refused by design (415). Audio only | Whatever you build | Yes, core product | Yes, core product | Yes |
| What you add to your stack | One container, no database, no queue | A table, a job queue, a backfill | A vendor and its pricing | A vendor and its pricing | A vendor plus your orchestration |
| What it costs | Apache-2.0. Your compute and storage | Your compute, storage, and the cruft's upkeep | Usage-based | Usage-based | Per-job, usage-based |
Cells reflect each product's documented public surface at the time of writing, checked against their own documentation rather than assumed. Corrections welcome: this page loses its value the moment a cell flatters us.
This is the real competitor. Which one wins depends on where you start, not on which design is nicer.
Have a working setup with one small hole? Patch it. A fixed clip shape is a small model and a background job, no new runtime dependency. A team in exactly this spot told us the payoff for a nicer design is clearer once the current approach actually costs something. They were right. Revisit when it stops being cheap: variants multiplying across formats and trims, a backfill after every rule change, a variants table growing columns nobody remembers.
Nothing built yet? The comparison flips. Pre-generating is a schema, a job, and a backfill strategy, designed before you know which variants you will need. One container makes a variant a URL: a new preview shape is a changed URL, not a migration.
Either way: adopt it for the jobs you have today. Optionality you will not use yet is worth nothing.
Cloudinary invented transformation URLs; audioproxy borrows the idea gratefully, via imgproxy. But audio is a side stage there: waveform images instead of waveform data, volume instead of loudness targets, derived assets in their storage at their prices. Want a managed everything-CDN where video leads? Cloudinary is a fine answer. Want audio-first with files in your own bucket? That is why this project exists.
If video is your product, use Mux. It is excellent, and audioproxy refuses video on purpose (415, before any render starts). The teams that switch are not leaving Mux the video platform. They are leaving Mux as an accidental audio pipeline: video prices for audio jobs, and no waveform data for their players.
MediaConvert and Transloadit shine when the work is known ahead of time: transcode the archive tonight, three formats, this bucket. audioproxy is the opposite bet: render what someone asks for, when they ask, and cache it. Archive migration is a batch job. Serving listeners is not.
A working setup with one small hole: patch it, keep your dependency count where it is. Video in the critical path: Mux or Cloudinary. Zero appetite for running anything: a managed vendor, priced accordingly. Bulk archive conversion: a batch pipeline. We would rather you pick right for your situation than adopt early and resent the container.
The fair objection to a new dependency is not whether it holds up but what you only meet once it is in. So meet it first: the explorer on the front page runs against a real deployment, and one docker command runs the same container against your own files, read-only, in about a minute. Nothing to install in your app, nothing to de-risk later.
Built by Julian Rubisch, an independent developer in Vienna. Available for Rails and Hotwire work through Rails Reviews.
Other things I make:Better Stimulus,Discover Bandcamp Labels,Crow's Nest,SoundLogo,resonAIte.