# Audio to MIDI Converter (Basic Pitch) (`jumblemog/audio-to-midi`) Actor

Convert songs, recordings and stems to MIDI files with Spotify's Basic Pitch AI. Polyphonic transcription for piano, guitar, bass, vocals and any instrument, with tempo and key detection, a note list in JSON and an audio preview. MP3, WAV, FLAC, M4A, video and more.

- **URL**: https://apify.com/jumblemog/audio-to-midi.md
- **Developed by:** [Jumble Mog](https://apify.com/jumblemog) (community)
- **Categories:** AI, For creators, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Audio to MIDI Converter (Basic Pitch)

**Convert songs, recordings and stems into MIDI files** with [Basic Pitch](https://basicpitch.spotify.com), the open-source note-transcription AI from Spotify's Audio Intelligence Lab. Give it an MP3, WAV, FLAC, M4A or even a video, and get back a standard **.mid file** you can drop into Ableton, FL Studio, Logic, GarageBand, MuseScore or any DAW, plus the **tempo**, the **key**, a **JSON list of every note** and an **MP3 preview** of the transcription. Polyphonic (chords work), any instrument, no GPU and no plugin to install.

![Spectrogram of a piano recording above the MIDI notes transcribed from it](https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/audio-to-midi-waltz.jpg?signature=1LJ3uBRcuU2UwfYnSPeBK)

Listen: [the piano recording (20 s)](https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/audio-to-midi-waltz-original.mp3?signature=1oFPY8fWNYdamQrR3VGZc), the [transcribed notes played back](https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/audio-to-midi-waltz-preview.mp3?signature=14Kw2RKyAzCxvUsatyZ9a), and [the MIDI file](https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/audio-to-midi-waltz.mid?signature=1buHKWAH3M3WcomaBH9zZ) for the whole piece (1,113 notes, key detected as A minor, correct). *Sample: Chopin, Waltz No. 19 in A minor, recorded by Musopen (CC0).*

### What it does

- **Transcribes notes, chords and melodies** from any instrument or voice: piano, guitar, bass, strings, winds, synths and singing.
- **MIDI that lines up with your DAW**: the tempo is detected and written into the file, so bars and beats match the recording. Or set the tempo yourself.
- **Instrument presets**: piano, guitar, bass or vocals limit notes to the instrument's range (fewer stray notes) and set a fitting MIDI sound.
- **Single melody line** for vocals, whistling and solo melodies: one note at a time, the loudest wins.
- **Pitch bends** (optional) follow slides, vibrato and bent guitar strings.
- **Key detection**: the most likely key (for example "E minor"), worked out from the transcribed notes.
- **Note list as JSON**: start and end in seconds, MIDI pitch, note name (C4, F#3...) and velocity for every note, ready for code, analysis and AI agents.
- **MP3 preview** that plays the transcribed notes, so you can check the result without opening a DAW.
- **Takes files from anywhere**: direct links, Google Drive and Dropbox share links, or uploads. Audio and video files up to 2 GB and 30 minutes.
- **Fast and cheap**: a 2-minute piano piece takes about 10 seconds. You pay per minute of audio; files that fail cost nothing.

### Who it's for

- **Producers and beatmakers** who want the MIDI of a riff, bassline, chord progression or melody to edit, re-voice or layer.
- **Musicians and teachers** turning recordings into notes to learn, arrange or notate (open the MIDI in MuseScore for sheet music).
- **Songwriters** capturing hummed or sung ideas as MIDI.
- **App developers and AI agents** adding music transcription, key and tempo detection to their products and workflows.
- **Music researchers** extracting notes from many recordings at once.

### How to use it

1. Paste links to audio or video files, or upload them. For the cleanest MIDI, use a recording of one instrument or a separated stem (vocals, bass, piano).
2. Pick the instrument, or keep "any instrument".
3. Click **Start**. Each file appears in the **Output** tab with links to the MIDI file, the note list and the preview.

You can also run it through the [Apify API](https://docs.apify.com/api/v2), on a schedule, or from Make, n8n, Zapier and other integrations.

### How-to examples

#### How to convert an MP3 or WAV to MIDI

```json
{"audioUrls": ["https://example.com/recordings/piano-waltz.mp3"], "instrument": "piano"}
```

Result: a .mid file in `midiUrl` with the tempo written in, so bars line up in your DAW, plus a JSON note list, an MP3 preview of the notes, the detected `key` and `notesFound`. A 2-minute piano piece takes about 10 seconds.

#### How to turn a bassline or guitar stem into MIDI

```json
{"audioUrls": ["https://example.com/stems/bassline.wav"], "instrument": "bass"}
```

Result for a 95-second bass stem: 212 notes from E1 to A3, a detected tempo of 112.3 BPM and the key of E minor. The bass preset keeps notes in the bass's range, so fewer stray notes come through.

#### How to transcribe a sung melody to MIDI

```json
{"audioUrls": ["https://drive.google.com/file/d/YOUR_FILE_ID/view?usp=sharing"], "instrument": "vocals", "singleMelody": true, "pitchBends": true}
```

Result: one note at a time (the loudest wins), with pitch bends that follow slides and vibrato. For a song with a band, separate the vocals first, for example with [Vocal Remover](https://apify.com/jumblemog/vocal-remover).

#### How to let an AI agent read the notes of a recording

Add this Actor to the [Apify MCP server](https://mcp.apify.com) with `https://mcp.apify.com/?tools=jumblemog/audio-to-midi`. The note list (`notesUrl`) gives every note's start, end, pitch, name and velocity, so the agent can work out chords, the key or a melody without listening.

### FAQ

**Which model does it use?** Basic Pitch, Spotify's open-source note-transcription model. It handles chords and several notes at once.

**Does it work on full songs?** It does, but every instrument's notes end up in one track, with some wrong ones. One instrument or a separated stem gives the cleanest MIDI.

**Can it transcribe drums?** No. It transcribes pitched notes.

**Which files work?** MP3, WAV, FLAC, M4A and other audio files, and video files, up to 2 GB and 30 minutes, from links, Google Drive, Dropbox or uploads.

**Does it work with Zapier, Make or n8n?** Yes. Call the Actor with its Apify app or an HTTP request and pass `midiUrl` on.

### Input

| Field | What it does |
| --- | --- |
| `audioUrls` | Links to audio or video files, or Google Drive and Dropbox share links. |
| `files` | Files uploaded from your computer or picked from an Apify key-value store. |
| `instrument` | `auto` (default, full range), `piano`, `guitar`, `bass` or `vocals`. |
| `sensitivity` | `normal` (default), `high` for soft and fast notes, `low` for clear notes only. |
| `minNoteMs` | Notes shorter than this are dropped (default 128 ms). |
| `singleMelody` | `true` keeps one note at a time, for vocals and solo melodies. |
| `pitchBends` | `true` adds pitch bends for slides and vibrato. |
| `tempoBpm` | Empty (default) detects the tempo; or set one, such as `120`. |
| `saveNoteList` | Save the JSON note list (default `true`). |
| `savePreview` | Save the MP3 preview (default `true`). |
| `maxFiles` | Stop after this many files (default 100). |

Example:

```json
{
  "audioUrls": [
    "https://example.com/stems/bassline.wav",
    "https://drive.google.com/file/d/YOUR_FILE_ID/view?usp=sharing"
  ],
  "instrument": "bass"
}
```

### Output

Each file becomes one dataset item, and the files are saved in the run's key-value store:

```json
{
  "url": "https://example.com/stems/bassline.wav",
  "status": "ok",
  "error": null,
  "midiUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-bassline.mid?signature=...",
  "notesUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-bassline-notes.json?signature=...",
  "previewUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-bassline-preview.mp3?signature=...",
  "fileName": "001-bassline.mid",
  "durationSeconds": 95.4,
  "notesFound": 212,
  "lowestNote": "E1",
  "highestNote": "A3",
  "tempoBpm": 112.3,
  "tempoDetected": true,
  "key": "E minor",
  "instrument": "bass",
  "minutesBilled": 2,
  "processingSeconds": 4.1
}
```

The note list file:

```json
{
  "tempoBpm": 112.3,
  "key": "E minor",
  "durationSeconds": 95.4,
  "notes": [
    {"start": 0.522, "end": 0.871, "pitch": 40, "name": "E2", "velocity": 92},
    {"start": 0.894, "end": 1.103, "pitch": 43, "name": "G2", "velocity": 78}
  ]
}
```

A file that couldn't be downloaded or read gets `status: "failed"` and an `error` that says why, and isn't billed. Download your files within your plan's data retention period, or copy them to your own storage, because run storage expires.

### Pricing

You pay per **started minute of audio**, at the price shown on this page. A 3-minute song is 3 minutes; a 20-second clip is 1 minute. Files that fail are never charged. If you set a maximum cost per run, the Actor stops before a file that wouldn't fit.

### Speed

Measured on Apify at the default 2 GB of memory: a 2-minute piano piece took about 10 seconds and a 20-second clip about 2 seconds, plus a few seconds to start the run. Transcription runs on the CPU, and giving the run more memory gives it more CPU.

### Tips and limits

- **One instrument at a time works best.** A full band mix gives a MIDI file with every instrument's notes in one track, including some wrong ones. Separate the stems first (for example the vocals or bass) for clean results. Drums aren't transcribed.
- Use the **instrument** preset to cut stray notes outside the instrument's range, and **single melody line** for singing.
- The MIDI keeps the performance's exact timing; it isn't quantized to the grid. Quantize in your DAW if you need it.
- The tempo is an estimate. Rubato and tempo changes can make it differ from the written tempo; set `tempoBpm` if you know it.
- Only the first audio track of a file is used, mixed to mono.
- Links to YouTube, TikTok, Instagram, SoundCloud and Spotify aren't supported, because those platforms' terms don't allow downloading. Use your own copy of the file.

### For AI agents and developers

This Actor works with the [Apify MCP server](https://mcp.apify.com), so AI agents can call it as a tool: pass `audioUrls` and read `midiUrl`, `key`, `tempoBpm` or the note list from each dataset item. Every item has the same documented fields, and `status` tells you whether a file succeeded. For a direct API call:

```bash
curl -X POST "https://api.apify.com/v2/acts/jumblemog~audio-to-midi/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"audioUrls": ["https://example.com/melody.mp3"], "singleMelody": true}'
```

### Privacy

Files are downloaded into the run, processed there and saved only to your own Apify storage. Nothing is sent to an outside service.

### Credits

- Note transcription: [Basic Pitch](https://github.com/spotify/basic-pitch) by Spotify's Audio Intelligence Lab (Apache-2.0), from the paper "A Lightweight Instrument-Agnostic Model for Polyphonic Note Transcription and Multipitch Estimation" (Bittner et al., ICASSP 2022). This Actor isn't affiliated with or endorsed by Spotify.
- Tempo estimation: [librosa](https://librosa.org). MIDI writing: [pretty_midi](https://github.com/craffel/pretty-midi). Audio decoding: [FFmpeg](https://ffmpeg.org).

# Actor input Schema

## `audioUrls` (type: `array`):

Direct links to audio or video files (MP3, WAV, FLAC, M4A, OGG, MP4, MOV and more), or Google Drive and Dropbox share links. YouTube, TikTok, Instagram, SoundCloud and Spotify links aren't supported because their terms don't allow downloading.

## `files` (type: `array`):

Upload audio or video files from your computer, or pick files you already stored in an Apify key-value store.

## `instrument` (type: `string`):

Limits notes to the instrument's range and sets the MIDI track's sound. auto keeps every note from the full range.

## `sensitivity` (type: `string`):

high catches soft and fast notes (and a few more wrong ones), low keeps only clear notes. normal suits most recordings.

## `minNoteMs` (type: `integer`):

Notes shorter than this are dropped. Lower it for fast passages, raise it to clean up busy transcriptions.

## `singleMelody` (type: `boolean`):

Keep one note at a time (the loudest), for singing, whistling and solo wind or string melodies.

## `pitchBends` (type: `boolean`):

Add MIDI pitch bends that follow slides, vibrato and bent strings.

## `tempoBpm` (type: `integer`):

Leave empty to detect the tempo, so the MIDI file lines up with your DAW's bars and beats. Or set the song's tempo yourself. Note timing is the same either way.

## `saveNoteList` (type: `boolean`):

Also save every note with start, end, pitch, note name and velocity as JSON.

## `savePreview` (type: `boolean`):

Also save an MP3 that plays the transcribed notes, so you can hear the result without a DAW.

## `maxFiles` (type: `integer`):

Stop after this many files, so the cost of a run stays predictable.

## Actor input object example

```json
{
  "audioUrls": [
    "https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/audio-to-midi-waltz-original.mp3?signature=1oFPY8fWNYdamQrR3VGZc"
  ],
  "instrument": "auto",
  "sensitivity": "normal",
  "minNoteMs": 128,
  "singleMelody": false,
  "pitchBends": false,
  "saveNoteList": true,
  "savePreview": true,
  "maxFiles": 100
}
```

# Actor output Schema

## `results` (type: `string`):

One item per file: MIDI, note list and preview links, number of notes, tempo and key.

## `files` (type: `string`):

The MIDI files, JSON note lists and MP3 previews saved in the run's key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "audioUrls": [
        "https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/audio-to-midi-waltz-original.mp3?signature=1oFPY8fWNYdamQrR3VGZc"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jumblemog/audio-to-midi").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "audioUrls": ["https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/audio-to-midi-waltz-original.mp3?signature=1oFPY8fWNYdamQrR3VGZc"] }

# Run the Actor and wait for it to finish
run = client.actor("jumblemog/audio-to-midi").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "audioUrls": [
    "https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/audio-to-midi-waltz-original.mp3?signature=1oFPY8fWNYdamQrR3VGZc"
  ]
}' |
apify call jumblemog/audio-to-midi --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jumblemog/audio-to-midi"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ojGfZ8v61gB32ihTn/builds/G4FoUyGVKhZMDVZLk/openapi.json
