PDF-to-Audiobook Converter

Convert any PDF book into a natural-sounding MP3 audiobook with Python.

Introduction

30 Second Summary

You have a bookshelf full of PDFs you never get around to reading. What if you could turn any of them into an audiobook and listen while commuting, cooking, or walking the dog?

In this project, you will build a Python script that converts any book PDF into a natural-sounding MP3 file. You will extract text, clean it up, and generate audio using both robotic and neural text-to-speech voices.

What You'll Build

You will run a single command on a book PDF and hear it read back to you in a natural Microsoft neural voice, ready to transfer to your phone or any music player.

By the end of this project, you'll have:

  • A working command that turns any PDF book into a listenable MP3 file using a natural neural voice you can play on your phone, in your car, or through any music app.
  • The ability to switch between a robotic offline voice and a natural neural voice with a simple flag, hearing the dramatic quality difference firsthand.
  • A text-cleaning pipeline that strips page numbers, running headers, and hyphenated line breaks so your audiobook narration flows smoothly.
  • Secret Mission: Add a full CLI with voice selection from 300+ voices, adjustable reading speed, and a live progress bar showing conversion status.

Are there any prerequisites?

None. This guide includes setup instructions for every tool you need, including Python, VS Code, and all required packages.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters to you.

Set Up Your Project

To build a PDF-to-audiobook converter, you need a Python project with the right packages installed. Your script will rely on three libraries: one for reading PDF text, one for offline robotic speech, and one for natural neural voices.

In this step, you will create a project folder, set up a virtual environment, install the required system and Python packages, and verify everything works together.

In this step, get ready to:
  • Create your project folder and virtual environment.
  • Install espeak-ng and the Python packages for PDF extraction and text-to-speech.
  • Open the project in VS Code and verify all imports work.
Create your project folder and virtual environment

A dedicated project folder keeps all your audiobook converter files in one place. A virtual environment isolates your Python packages so they do not interfere with other projects on your machine.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir pdf-to-audiobook
cd pdf-to-audiobook
  • Create a virtual environment and activate it by running these commands:
python -m venv venv
source venv/bin/activate

Your terminal prompt now shows (venv) at the beginning. This confirms the virtual environment is active.

What is a virtual environment?

A virtual environment is an isolated Python installation inside your project folder. Packages you install here stay separate from your system Python.

This means you can use specific package versions for this project without affecting anything else on your computer.

Not seeing (venv) in your prompt?

Make sure you ran source venv/bin/activate (not just python -m venv venv). The first command creates the environment. The second command activates it.

If you see a "No such file or directory" error, confirm you are inside the pdf-to-audiobook folder by running pwd.

Help me activate my virtual environment.

Install espeak-ng and the Python packages

Your converter needs a system-level speech engine (espeak-ng) for offline robotic voice output. It also needs three Python libraries for PDF reading and text-to-speech.

  • Install the espeak-ng system packages by running this command:
sudo apt update && sudo apt install espeak-ng libespeak1

What will this command ask me?

Your system will ask for your password after sudo. Type it and press Enter (you will not see characters appear as you type).

If prompted with "Do you want to continue? [Y/n]", type Y and press Enter.

The output confirms both packages are set up and ready.

  • Install the three Python packages by running this command:
pip install pymupdf==1.28.0 pyttsx3==2.99 edge-tts==7.2.8

The output ends with a line confirming all three packages were successfully installed.

What do these packages do?

  • PyMuPDF (pymupdf) reads text from PDF files page by page.
  • pyttsx3 converts text to speech offline using espeak-ng. It produces a robotic but instant voice.
  • edge-tts connects to Microsoft's neural voice service for natural-sounding speech at no cost.

Seeing an installation error?

If pip install fails, make sure your virtual environment is active. You should see (venv) in your prompt. If not, run source venv/bin/activate again and retry the install.

If sudo apt install failed, check your internet connection and try running sudo apt update separately first.

Help me fix my package installation errors.

Open VS Code and verify your setup
  • Open VS Code in your project folder by running this command:
code .

VS Code opens with the pdf-to-audiobook folder visible in the Explorer sidebar.

  • Create an empty Python file for your script by running this command:
touch pdf_to_audio.py
  • Confirm the file exists by running:
ls

You should see pdf_to_audio.py and the venv folder in the output.

Now for the real test. Before you run the next command, what do you think will happen if all three packages installed correctly?

  • Verify all packages import correctly by running this command:
python -c "import pymupdf; import pyttsx3; import edge_tts; print('All good!')"

You should see All good! printed in your terminal. This confirms PyMuPDF, pyttsx3, and edge-tts are all installed and importable.

Seeing a ModuleNotFoundError?

This means one of the packages did not install into your active virtual environment. Check that (venv) shows in your prompt.

If it does, re-run the pip install command. If (venv) is missing, activate it with source venv/bin/activate and then run pip install pymupdf==1.28.0 pyttsx3==2.99 edge-tts==7.2.8 again.

Help me fix my ModuleNotFoundError.

Your project is set up and ready to go. Next up, you will extract text from a PDF and hear it read aloud for the first time.

Extract Text and Generate Robotic Audio

Your environment is set up and ready to go. Now it is time to make your script actually do something.

The fastest path to hearing your PDF read aloud is extracting its text and passing it straight to pyttsx3. You will get immediate audio output, but the robotic quality will be obvious. Text artifacts from the PDF (page numbers, repeated headers) will also be audible.

In this step, get ready to:
  • Write a function that extracts all text from a PDF using PyMuPDF.
  • Add offline text-to-speech that saves the extracted text as an MP3 file.
  • Run the script on a real PDF and hear the robotic voice read it aloud.
Write the PDF text extraction

Before you can generate audio, you need to pull the raw text out of a PDF file. PyMuPDF handles this by opening the document and reading each page's text content.

  • In VS Code, open pdf_to_audio.py and add the imports and extraction function by pasting this code:
import sys

import pymupdf
import pyttsx3


def extract_text(pdf_path):
    """Extract all text from a PDF file."""
    doc = pymupdf.open(pdf_path)
    pages_text = []
    for page in doc:
        pages_text.append(page.get_text())
    doc.close()
    return "\n\n".join(pages_text)

What does this code do?

The top section imports three modules: sys for reading command-line arguments, pymupdf for PDF parsing, and pyttsx3 for offline text-to-speech.

The extract_text() function opens a PDF, loops through every page, grabs the text with page.get_text(), and joins all page text together with double newlines as paragraph separators.

  • Save pdf_to_audio.py.
  • Verify the imports work by running this command in your terminal:
python -c "from pdf_to_audio import extract_text; print('extract_text loaded')"

You should see extract_text loaded printed with no errors.

Seeing an ImportError?

  • Make sure your virtual environment is active. You should see (venv) at the start of your terminal prompt.
  • Check that you saved the file before running the command. Unsaved changes are invisible to Python.
  • Confirm the import says import pymupdf (not import fitz). The pymupdf name is the recommended import for version 1.28.0.

Why isn't my pdf_to_audio module importing correctly?

Add pyttsx3 offline TTS and the main function

Now you need two more pieces: a function that converts text into speech audio, and a main() entry point that ties everything together.

  • Below extract_text() in pdf_to_audio.py, add the generate_robotic() function:
def generate_robotic(text, output_file):
    """Generate audio using pyttsx3 (offline, robotic)."""
    engine = pyttsx3.init()
    engine.save_to_file(text, output_file)
    engine.runAndWait()
    print(f"Saved robotic audio to {output_file}")

What does this code do?

This function initializes the pyttsx3 engine (which uses espeak-ng on Linux), queues the entire text for saving to an MP3 file, and then calls engine.runAndWait() to process the speech and write the file.

  • Below generate_robotic(), add the main() function and the entry-point block:
def main():
    if len(sys.argv) < 2:
        print("Usage: python pdf_to_audio.py <pdf_file>")
        sys.exit(1)

    pdf_path = sys.argv[1]

    print(f"Extracting text from {pdf_path}...")
    raw_text = extract_text(pdf_path)

    print("Generating robotic audio...")
    output_file = pdf_path.rsplit(".", 1)[0] + ".mp3"
    generate_robotic(raw_text, output_file)

    print("Done!")


if __name__ == "__main__":
    main()

What does this code do?

The main() function reads the PDF filename from the command line (sys.argv[1]), extracts its text, then passes it to generate_robotic(). The output filename is the same as the input but with .mp3 instead of .pdf.

The if __name__ == "__main__" block ensures main() only runs when you execute the script directly, not when importing it as a module.

  • Save pdf_to_audio.py.

✔️ Awesome, I've got everything!

Great. Double check you have saved your file before moving on.

ⓧ I'd like to double check the full code

Scroll up and confirm your file contains these three sections in order:

  • Imports (sys, pymupdf, pyttsx3) at the top.
  • The extract_text() function.
  • The generate_robotic() function.
  • The main() function followed by the if __name__ == "__main__" block.
Test with a sample PDF

You need any PDF book or document to test with. Use any PDF you already have on your computer.

No PDF handy?

Search for any free, public domain PDF book online. Anything with a few pages of text will work for testing.

  • Copy a PDF file into your pdf-to-audiobook folder. For the examples below, it is named sample.pdf but yours can be any name.
  • Confirm the file is there by running:
ls *.pdf

You should see your PDF filename listed.

Before you run the converter, predict what you expect to happen. Will the audio sound natural, or robotic? Will page numbers and headers show up in the narration?

  • Run your script on the PDF by running this command (replace sample.pdf with your actual filename):
python pdf_to_audio.py [[PDFFILE="your-pdf-filename.pdf"]]

You should see output like this:

Extracting text from sample.pdf...
Generating robotic audio...
Saved robotic audio to sample.mp3
Done!
  • Confirm the MP3 file was created by running:
ls *.mp3

You should see a file like sample.mp3 (matching your input filename but with the .mp3 extension).

  • Open the MP3 in any audio player and listen to a few seconds of it.

The voice is clearly robotic. You will also hear page numbers read aloud as words, repeated headers every few seconds, and hyphenated words split awkwardly across line breaks. Those are all PDF text artifacts being narrated verbatim.

No audio file created?

  • Make sure espeak-ng is installed. Run espeak-ng --version to check.
  • Confirm the PDF is a real text-based PDF, not a scanned image. Scanned PDFs contain no extractable text.
  • Check your terminal for error messages. A missing libespeak-ng.so.1 error means espeak-ng was not installed correctly in Step 1.

Why is pyttsx3 not producing an audio file from my PDF?

You have a working PDF-to-audio pipeline. The voice gets the job done, but it is robotic and every PDF artifact gets narrated. Next up, you will swap in a neural voice that sounds dramatically more natural.

Upgrade to Neural Voices

In the previous step, you extracted text from a PDF and heard it read aloud by pyttsx3. The audio works, but it sounds undeniably robotic.

Now you will add edge-tts, a free library that uses Microsoft's neural voices. The quality jump is dramatic. The neural voice sounds almost human, but it also exposes a new problem: text artifacts like page numbers and headers become painfully obvious when a natural-sounding voice reads them aloud.

In this step, get ready to:
  • Add an async neural voice function using edge-tts.
  • Add a --voice flag to switch between robotic and neural engines.
  • Compare both voices on the same PDF and hear the quality difference firsthand.
Add edge-tts as an alternative TTS engine

The edge-tts library connects to Microsoft's neural TTS service over the internet. It uses an async API, which means you need Python's asyncio module to run it.

  • In pdf_to_audio.py, find the imports at the top of the file:
import sys

import pymupdf
import pyttsx3
  • Replace the import section with this updated version that adds asyncio and edge_tts:
import sys
import asyncio

import pymupdf
import pyttsx3
import edge_tts

What are these two new imports?

asyncio is Python's built-in module for running asynchronous code. The edge-tts library is async-only, so you need asyncio to call it.

edge_tts is the library that connects to Microsoft's neural voice service. It gives you access to 300+ natural-sounding voices for free.

  • Now add the neural voice function below the generate_robotic function by copying this code:
async def generate_neural(text, output_file):
    """Generate audio using edge-tts (online, natural)."""
    communicate = edge_tts.Communicate(text, "en-US-AriaNeural")
    await communicate.save(output_file)
    print(f"Saved neural audio to {output_file}")

What does this function do?

  • async def marks this as an asynchronous function. It can pause while waiting for the network response without freezing your script.
  • edge_tts.Communicate(text, "en-US-AriaNeural") creates a communication object that will send your text to Microsoft's Aria neural voice.
  • await communicate.save(output_file) sends the text to the service and saves the returned audio directly to an MP3 file.
  • Save pdf_to_audio.py.
  • Confirm nothing is broken by running your script with the existing robotic voice:
python pdf_to_audio.py sample.pdf

You should still hear the robotic voice and see the same output as before. The new function exists but nothing calls it yet.

Seeing an import error?

  • Check that you spelled import edge_tts with an underscore, not a hyphen.
  • Make sure your virtual environment is active. You should see (venv) in your terminal prompt.

Help me debug this import error in my PDF to audio script.

Add a --voice flag to switch between engines

Right now your main() function always uses the robotic voice. You need a way to choose between robotic and neural at runtime.

  • Find the main() function in pdf_to_audio.py and replace it entirely with this updated version:
def main():
    if len(sys.argv) < 2:
        print("Usage: python pdf_to_audio.py <pdf_file> [--voice robotic|neural]")
        sys.exit(1)

    pdf_path = sys.argv[1]

    # Parse --voice flag
    voice_type = "neural"
    if "--voice" in sys.argv:
        voice_index = sys.argv.index("--voice") + 1
        if voice_index < len(sys.argv):
            voice_type = sys.argv[voice_index]

    print(f"Extracting text from {pdf_path}...")
    raw_text = extract_text(pdf_path)

    print(f"Generating {voice_type} audio...")
    output_file = pdf_path.rsplit(".", 1)[0] + ".mp3"

    if voice_type == "robotic":
        generate_robotic(raw_text, output_file)
    else:
        asyncio.run(generate_neural(raw_text, output_file))

    print("Done!")

What does this updated main() do?

  • The usage string now shows the --voice option so the learner knows how to use it.
  • voice_type = "neural" sets neural as the default. You get the best voice unless you explicitly ask for robotic.
  • The if "--voice" in sys.argv block checks whether the flag was passed and grabs the value after it.
  • asyncio.run(generate_neural(...)) is how you call an async function from regular (synchronous) code. It starts the async event loop and runs your function.
  • Save pdf_to_audio.py.

Not sure where main() ends?

The main() function starts at def main(): and ends just before if __name__ == "__main__":. Replace everything between those two lines.

Help me find where to replace the main function in my script.

Test both voices on the same PDF and compare

Now for the moment of truth. You will run your script twice on the same PDF and hear the difference between the two voices.

  • First, run with the robotic voice to remind yourself what it sounds like:
python pdf_to_audio.py sample.pdf --voice robotic

Listen to the output MP3. This is the same pyttsx3 engine from the previous step.

Before you run the neural version, what do you think will be different? Will it sound completely polished, or might there still be problems?

  • Now run with the neural voice:
python pdf_to_audio.py sample.pdf --voice neural

You should see output like this:

Extracting text from sample.pdf...
Generating neural audio...
Saved neural audio to sample.mp3
Done!

Listen to the new MP3. The voice quality is strikingly natural. But listen closely for something odd: the voice confidently reads out page numbers, running headers, and words awkwardly split across lines. These artifacts were easy to ignore in the robotic version, but with a natural voice they are jarring.

Why do artifacts sound worse with a better voice?

When a robotic voice reads "forty-two" between paragraphs, your brain dismisses it as noise. When a natural, human-sounding voice reads it with proper intonation, your brain tries to make sense of it as part of the narrative. The better the voice, the more distracting the garbage text becomes.

You will fix this in the next step by building a text-cleaning pipeline.

Getting a connection error?

  • The neural voice requires an internet connection. Check that you are connected to the internet.
  • If you are behind a corporate firewall or VPN, try disconnecting from it temporarily.
  • Make sure you spelled --voice neural correctly. A typo would still route to the neural path (since anything other than "robotic" defaults to neural) but would not cause a connection error.

Help me fix this edge-tts connection error.

✔️ Awesome, I've got everything!

Great. Double check you have saved pdf_to_audio.py and both voices produce output when you run the script.

ⓧ I'd like to double check the full code

Scroll through your pdf_to_audio.py and confirm these sections appear in order:

  • Imports: sys, asyncio, pymupdf, pyttsx3, edge_tts.
  • extract_text() function: unchanged from the previous step.
  • generate_robotic() function: unchanged from the previous step.
  • generate_neural() function: new async function using edge_tts.Communicate with en-US-AriaNeural.
  • main() function: parses --voice flag, defaults to neural, routes to generate_robotic or generate_neural.
  • if __name__ == "__main__": calls main().

The neural voice proves the concept works. Your PDF can be read aloud in a voice that sounds almost human. But those text artifacts are ruining the experience. Next up, you will build a cleaning pipeline that strips page numbers, headers, and hyphenation so the narration flows like a real audiobook.

Clean the Text for Smooth Narration

In the previous step, you upgraded to a natural neural voice. The quality jump was dramatic, but it also made a new problem impossible to ignore.

Page numbers being read aloud as words, repeated headers every few seconds, and hyphenated words broken across lines all ruin the listening experience. Now you will build a text-cleaning pipeline using regex that strips these artifacts before the text reaches the voice engine.

In this step, get ready to:
  • Build a clean_text() function that removes page numbers, fixes hyphenation, and normalizes whitespace.
  • Wire the cleaning step into your main pipeline so text is cleaned before reaching the voice engine.
  • Test the cleaned audio and hear the difference compared to the raw version.
Build the clean_text() function

PDF text extraction pulls out raw content exactly as it appears on the page. That means standalone page numbers, words split with hyphens across lines, and inconsistent newlines all end up in your text.

You will use Python's re module (regular expressions) to detect and remove these patterns automatically.

  • In pdf_to_audio.py, find the import section at the top of the file. Add import re on a new line directly after import asyncio.
  • Then, add the following clean_text() function directly below your extract_text() function:
def clean_text(text):
    """Clean extracted PDF text for natural speech."""
    # Remove standalone page numbers (lines that are just digits)
    text = re.sub(r"^\s*\d+\s*$", "", text, flags=re.MULTILINE)

    # Fix hyphenated line breaks (word- \n continuation)
    text = re.sub(r"(\w)-\s*\n\s*(\w)", r"\1\2", text)

    # Replace single newlines within paragraphs with spaces
    text = re.sub(r"(?<!\n)\n(?!\n)", " ", text)

    # Collapse multiple spaces into one
    text = re.sub(r" {2,}", " ", text)

    # Collapse 3+ newlines into 2 (paragraph break)
    text = re.sub(r"\n{3,}", "\n\n", text)

    # Strip leading/trailing whitespace
    text = text.strip()

    return text

What does each regex pattern do?

  • Line 1 strips page numbers. It matches any line that is only whitespace and digits, then replaces it with nothing.
  • Line 2 fixes hyphenated line breaks. When a word is split across two lines with a hyphen (like "auto-\nmatic"), this joins them back into one word ("automatic").
  • Line 3 turns single newlines into spaces. PDFs insert a newline at the end of every visual line, but for speech these should flow as one sentence.
  • Lines 4-5 normalize whitespace. Multiple spaces become one, and triple-or-more newlines collapse to a double newline (a paragraph break).
  • Save pdf_to_audio.py.

Seeing a syntax error in your regex?

Make sure every regex string uses a raw string prefix (r"..."). Without the r, Python interprets backslashes as escape characters instead of passing them to the regex engine.

Help me fix my regex pattern

Wire cleaning into the pipeline

The function exists but nothing calls it yet. You need to insert a cleaning step between text extraction and audio generation in main().

  • In your main() function, find this line:
    raw_text = extract_text(pdf_path)

    print(f"Generating {voice_type} audio...")
  • Add two new lines between raw_text = extract_text(pdf_path) and the print(f"Generating... line, so it looks like this:
    raw_text = extract_text(pdf_path)

    print("Cleaning text...")
    text = clean_text(raw_text)

    print(f"Generating {voice_type} audio...")
  • Now find the two lines near the bottom of main() that pass raw_text to the generate functions:
        generate_robotic(raw_text, output_file)
    else:
        asyncio.run(generate_neural(raw_text, output_file))
  • Replace raw_text with text in both of those lines, so they now read:
        generate_robotic(text, output_file)
    else:
        asyncio.run(generate_neural(text, output_file))

Why a separate variable?

You keep raw_text and create a new text variable rather than overwriting. This makes it easy to compare the two versions later or add a debug flag that skips cleaning.

  • Save pdf_to_audio.py.
Test the cleaned output

Before you run this, think about what you expect to hear differently. In the previous step, the neural voice read out page numbers and narrated hyphenated fragments. What do you think happens now that those patterns are being stripped?

  • Run the script on your sample PDF with the neural voice by running this command:
python pdf_to_audio.py sample.pdf --voice neural

You should see output like this:

Extracting text from sample.pdf...
Cleaning text...
Generating neural audio...
Saved neural audio to sample.mp3
Done!

Notice the new "Cleaning text..." line confirming your pipeline now runs the cleaning step. Play the sample.mp3 file and listen. Page numbers are gone. Hyphenated words flow as complete words. Sentences connect naturally without odd pauses from stray newlines.

Compare with the robotic voice too

Run with --voice robotic to hear how cleaning helps even the robotic engine. The improvement is subtle there but dramatic with the neural voice.

Still hearing page numbers or broken words?

Make sure you changed both raw_text references in the if/else block to text. If only one was changed, the other voice path still uses uncleaned text.

Also check that your clean_text() function is placed between extract_text() and generate_robotic() in the file. Python reads top-to-bottom, so the function must be defined before main() calls it.

Help me debug my text cleaning

✔️ Awesome, I've got everything!

Great. Double check you have saved pdf_to_audio.py and that your terminal showed all four status lines when you ran the script.

ⓧ I'd like to double check the full code

Scroll up and confirm your file has these sections in order:

  • Imports: sys, asyncio, re, then pymupdf, pyttsx3, edge_tts.
  • extract_text() function (unchanged from the previous step).
  • clean_text() function with 6 regex operations (page numbers, hyphenation, single newlines, multiple spaces, 3+ newlines, strip).
  • generate_robotic() and generate_neural() functions (unchanged).
  • main() with text = clean_text(raw_text) between extraction and generation, passing text (not raw_text) to both generate functions.

Your audiobook converter now produces clean, natural audio from any book PDF. Next up, you will tackle the Secret Mission and turn this script into a full CLI tool with voice selection, speed control, and a progress bar.

Secret mission

Add a Full CLI with Voice Selection, Speed Control, and Progress Bar

Your converter works, but a real tool needs a proper interface. Can you add voice selection from 300+ voices, adjustable reading speed, and a live progress bar that shows conversion status chunk by chunk?

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

This project runs entirely locally, so there are no ongoing costs.

Resources you used:

  • Virtual environment in pdf-to-audiobook/venv/ (no cost, local only).
  • espeak-ng system package (no cost).
  • Output MP3 files in your project directory (local only).

Keep everything running

No action needed. Choose this if you plan to convert more PDFs or experiment with different voices and speeds.

  • Your virtual environment and packages stay on your system.
  • The espeak-ng package remains installed for offline TTS.
  • Any generated MP3 files remain in your project folder.

Pause - I'll come back to this later

Deactivate the virtual environment to free up your terminal. Your project files stay intact for when you return.

  • Deactivate the virtual environment by running:
deactivate
  • When you come back, reactivate with source venv/bin/activate from inside your pdf-to-audiobook folder.

Delete - I don't want to use this again

Remove all project files and optionally uninstall the system package.

  • Deactivate the virtual environment and delete the entire project folder by running:
deactivate
cd ~/Desktop
rm -rf pdf-to-audiobook
  • Optionally, remove the espeak-ng system package by running:
sudo apt remove espeak-ng libespeak1
  • Delete any output MP3 files you generated outside the project folder.

That's a Wrap!

That's a Wrap!

Nice work! You just built a fully functional PDF-to-audiobook converter that turns any book into a natural-sounding MP3 file you can listen to anywhere.

You've learned how to:

  • Build a working PDF-to-audiobook converter that extracts text with PyMuPDF and produces natural-sounding MP3 files using Microsoft neural voices.
  • Compare robotic (espeak-ng/pyttsx3) and neural (edge-tts) text-to-speech engines, switching between them with a simple flag.
  • Write a text-cleaning pipeline using regex to strip page numbers, headers, and hyphenated line breaks so narration flows like a real audiobook.
  • Secret Mission: Added a full CLI with voice selection from 300+ voices, adjustable reading speed, and a live progress bar showing conversion status.

Ready to quiz yourself?