Toolmingo
Guides7 min read

How to Convert Audio Files (MP3, WAV, FLAC, AAC, OGG)

Learn how to convert between audio formats like MP3, WAV, FLAC, AAC, OGG, and M4A — with code examples in JavaScript, Python, Go, and PHP, plus ffmpeg CLI.

Audio conversion is one of the most common file tasks: a podcast editor needs WAV from a voice memo, a game dev needs OGG from MP3, a music fan wants FLAC from M4A. Each format makes different trade-offs between file size, quality, and compatibility — and converting between them correctly takes more than just renaming an extension.

Audio format quick reference

Format Type Typical use Avg. size (3 min song)
MP3 Lossy Universal compatibility, streaming 3–8 MB
AAC / M4A Lossy Apple ecosystem, YouTube, better quality/size than MP3 3–6 MB
OGG (Vorbis) Lossy Web browsers, games (royalty-free) 3–6 MB
WAV Lossless (PCM) Studio editing, no compression 30–50 MB
FLAC Lossless Archiving, audiophile playback 15–30 MB
AIFF Lossless (PCM) macOS / Pro Tools editing 30–50 MB
OPUS Lossy VoIP, Discord, low-bitrate streaming 1–3 MB

Key rule: converting lossy → lossy (MP3 → OGG) re-encodes and adds generation loss. Always archive from the highest-quality source available.

Converting with ffmpeg (CLI)

ffmpeg is the Swiss army knife of media conversion. Install it once and use it everywhere.

# MP3 → WAV (lossless PCM)
ffmpeg -i input.mp3 output.wav

# WAV → MP3 at 192 kbps
ffmpeg -i input.wav -b:a 192k output.mp3

# FLAC → AAC at 256 kbps
ffmpeg -i input.flac -c:a aac -b:a 256k output.m4a

# MP4 / video → extract audio as MP3
ffmpeg -i input.mp4 -vn -b:a 192k output.mp3

# Batch: convert all FLAC in a folder to MP3
for f in *.flac; do ffmpeg -i "$f" -b:a 256k "${f%.flac}.mp3"; done

Flag cheat sheet:

Flag Meaning
-i Input file
-vn No video (audio only)
-c:a aac Audio codec (aac / libmp3lame / flac / pcm_s16le)
-b:a 192k Audio bitrate
-ar 44100 Sample rate
-ac 2 Channel count (2 = stereo)

JavaScript — browser (ffmpeg.wasm)

Convert audio entirely in the browser with no server upload using the @ffmpeg/ffmpeg package.

import { FFmpeg } from "@ffmpeg/ffmpeg";
import { fetchFile, toBlobURL } from "@ffmpeg/util";

const CORE = "https://unpkg.com/@ffmpeg/core@0.12.6/dist/umd";

async function convertAudio(
  file: File,
  targetFormat: "mp3" | "wav" | "ogg" | "m4a" | "aac"
): Promise<Blob> {
  const ffmpeg = new FFmpeg();
  await ffmpeg.load({
    coreURL: await toBlobURL(`${CORE}/ffmpeg-core.js`, "text/javascript"),
    wasmURL: await toBlobURL(`${CORE}/ffmpeg-core.wasm`, "application/wasm"),
  });

  const ext = file.name.split(".").pop() ?? "mp3";
  const inputName = `input.${ext}`;
  const outputName = `output.${targetFormat}`;

  await ffmpeg.writeFile(inputName, await fetchFile(file));
  await ffmpeg.exec(["-i", inputName, "-b:a", "192k", outputName]);

  const data = await ffmpeg.readFile(outputName);
  const mimeMap: Record<string, string> = {
    mp3: "audio/mpeg",
    wav: "audio/wav",
    ogg: "audio/ogg",
    m4a: "audio/mp4",
    aac: "audio/aac",
  };
  return new Blob([data], { type: mimeMap[targetFormat] });
}

// Usage
const input = document.querySelector<HTMLInputElement>("#file")!.files![0];
const blob = await convertAudio(input, "mp3");
const url = URL.createObjectURL(blob);

Note: The first load downloads ~30 MB of WASM. Cache it with a service worker for repeat visits. ffmpeg.wasm is single-threaded in most browsers; large files (>100 MB) will block the UI — use a Web Worker.

JavaScript — Node.js (fluent-ffmpeg)

For server-side conversion, fluent-ffmpeg wraps the system ffmpeg binary:

import ffmpeg from "fluent-ffmpeg";

function convertAudio(inputPath, outputPath, bitrate = "192k") {
  return new Promise((resolve, reject) => {
    ffmpeg(inputPath)
      .noVideo()
      .audioBitrate(bitrate)
      .save(outputPath)
      .on("end", resolve)
      .on("error", reject);
  });
}

// MP3 → WAV
await convertAudio("input.mp3", "output.wav");

// FLAC → AAC
await convertAudio("input.flac", "output.m4a", "256k");

Python (pydub + ffmpeg)

pydub provides a high-level API over ffmpeg. Install with pip install pydub (ffmpeg must be on your PATH).

from pydub import AudioSegment
import os

def convert_audio(
    input_path: str,
    output_path: str,
    bitrate: str = "192k"
) -> None:
    """Convert any audio format to any other using pydub + ffmpeg."""
    ext = os.path.splitext(output_path)[1].lstrip(".")
    audio = AudioSegment.from_file(input_path)  # auto-detects input format
    audio.export(output_path, format=ext, bitrate=bitrate)

# Examples
convert_audio("input.mp3", "output.wav")          # WAV is lossless — ignore bitrate
convert_audio("input.flac", "output.mp3", "320k") # FLAC → MP3 at 320 kbps
convert_audio("input.m4a", "output.ogg", "160k")  # M4A → OGG

# Batch conversion: all WAV files → MP3
from pathlib import Path

for wav in Path(".").glob("*.wav"):
    convert_audio(str(wav), str(wav.with_suffix(".mp3")))

Tip: For WAV output, skip the bitrate argument — WAV is PCM and uncompressed bitrate is determined by sample rate × bit depth × channels.

Go (exec wrapper)

Go's standard library has no audio codec support; the idiomatic approach is to shell out to ffmpeg:

package main

import (
    "fmt"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
)

// ConvertAudio converts src to dst using ffmpeg.
// targetFormat: "mp3", "wav", "ogg", "m4a", "aac", etc.
// bitrate: "192k", "256k", "320k" (ignored for lossless WAV/FLAC)
func ConvertAudio(src, dst, bitrate string) error {
    args := []string{"-y", "-i", src}
    ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(dst), "."))

    switch ext {
    case "wav":
        args = append(args, "-c:a", "pcm_s16le") // lossless PCM
    case "flac":
        args = append(args, "-c:a", "flac")
    case "mp3":
        args = append(args, "-c:a", "libmp3lame", "-b:a", bitrate)
    default:
        args = append(args, "-b:a", bitrate) // aac / ogg / m4a
    }

    args = append(args, "-vn", dst) // -vn: strip video tracks

    cmd := exec.Command("ffmpeg", args...)
    cmd.Stderr = os.Stderr
    return cmd.Run()
}

func main() {
    if err := ConvertAudio("input.flac", "output.mp3", "256k"); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    fmt.Println("Done")
}

PHP (exec + ffmpeg)

<?php

function convertAudio(
    string $inputPath,
    string $outputPath,
    string $bitrate = '192k'
): bool {
    // Validate paths — never pass unsanitised user input to exec()
    foreach ([$inputPath, $outputPath] as $p) {
        if (!preg_match('/^[\w\-\/\\.]+$/', $p)) {
            throw new \InvalidArgumentException("Unsafe path: $p");
        }
    }

    $ext = strtolower(pathinfo($outputPath, PATHINFO_EXTENSION));

    $codecArgs = match ($ext) {
        'wav'  => '-c:a pcm_s16le',
        'flac' => '-c:a flac',
        'mp3'  => "-c:a libmp3lame -b:a {$bitrate}",
        default => "-b:a {$bitrate}",  // aac, ogg, m4a
    };

    $cmd = sprintf(
        'ffmpeg -y -i %s -vn %s %s 2>&1',
        escapeshellarg($inputPath),
        $codecArgs,
        escapeshellarg($outputPath)
    );

    exec($cmd, $output, $returnCode);
    return $returnCode === 0;
}

// Examples
convertAudio('input.mp3', 'output.wav');
convertAudio('input.flac', 'output.mp3', '320k');

Quick reference

Task ffmpeg command Library
MP3 → WAV ffmpeg -i in.mp3 out.wav pydub / fluent-ffmpeg
WAV → MP3 ffmpeg -i in.wav -b:a 192k out.mp3 pydub / fluent-ffmpeg
FLAC → AAC ffmpeg -i in.flac -c:a aac -b:a 256k out.m4a pydub
Video → MP3 ffmpeg -i in.mp4 -vn -b:a 192k out.mp3 fluent-ffmpeg
OGG → M4A ffmpeg -i in.ogg -b:a 192k out.m4a pydub
Browser convert ffmpeg.wasm
Batch (shell) for f in *.flac; do ... glob + pydub

6 common mistakes

1. Renaming the file extension instead of converting mv song.mp3 song.wav does not convert anything — the bytes stay as MP3. Always use a proper encoder.

2. Lossy → lossy re-encoding Going MP3 → OGG → MP3 compounds quality loss each time. Keep your master as WAV or FLAC and encode to lossy only for distribution.

3. Using the wrong codec for WAV WAV is a container — it can hold compressed audio. Specify -c:a pcm_s16le to guarantee standard uncompressed PCM that every player reads.

4. Forgetting -vn when extracting audio from video Without -vn, ffmpeg copies the video stream and fails if the output container (MP3) doesn't support it.

5. Setting a bitrate for lossless output -b:a 320k is meaningless for WAV or FLAC — they encode all audio data regardless. Omit -b:a for lossless targets.

6. Passing unsanitised user input to exec() If your PHP or Node.js code wraps ffmpeg, always validate or escapeshellarg() file paths. Arbitrary command injection via file names is a real attack vector.

Frequently asked questions

What is the best audio format for quality? For lossless archival: FLAC (smaller than WAV, same quality). For streaming at a given bitrate: AAC at 256 kbps edges out MP3; OPUS at 128 kbps beats both.

Does converting MP3 to WAV improve quality? No. WAV is lossless, but the quality ceiling is already set by the MP3 source. You get a larger file with the same audible quality — useful for editing in a DAW that requires PCM input, not for fidelity.

What bitrate should I use for MP3? 128 kbps for voice/podcasts, 192 kbps for music streaming, 320 kbps for archival/maximum quality. Most listeners cannot distinguish 192 kbps from 320 kbps in a blind test.

Can I convert a video file to audio? Yes. ffmpeg -vn strips the video stream and outputs only audio. ffmpeg -i input.mp4 -vn -b:a 192k output.mp3 works for any video container.

Why does OGG sound different from MP3 at the same bitrate? OGG Vorbis and MP3 use different psychoacoustic models. Vorbis is generally considered more efficient at low bitrates (below 128 kbps); the difference is minor at 192 kbps+.

Is it legal to convert M4A/AAC files I downloaded? Converting files you own for personal use is generally legal in most jurisdictions. Distribution or stripping DRM (FairPlay-protected iTunes purchases) is a different matter — check local law and the content's licence.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools