{
  "slug": "tempo-map-extractor",
  "name": "gizza-ai/tempo-map-extractor",
  "version": "0.1.0",
  "title": "Tempo Map Extractor — Beat Times to a BPM-vs-Time Curve — gizza.ai",
  "description": "Turn a list of beat times into a tempo map: BPM versus time, with smoothing, drift statistics and CSV, JSON, label-track or MIDI tempo exports.",
  "tags": [
    "tempo map extractor",
    "beat times to bpm",
    "bpm over time",
    "variable tempo curve",
    "tempo map csv",
    "beat times to tempo map",
    "bpm vs time",
    "tempo drift analysis"
  ],
  "category": "audio",
  "urls": {
    "page": "https://gizza.ai/tools/tempo-map-extractor/",
    "markdown": "https://gizza.ai/tools/tempo-map-extractor/index.md",
    "descriptor": "https://gizza.ai/tools/tempo-map-extractor/tool.json",
    "deep_link_example": "https://gizza.ai/tools/tempo-map-extractor/?beats=0.000%0A0.500%0A1.000%0A1.520%0A2.060&time_unit=auto&fps=30&beat_unit=quarter&smoothing=1&smooth_method=mean&decimals=2&output=csv&ppq=960"
  },
  "cli": "gizza tool tempo-map-extractor \"0.000\n0.500\n1.000\n1.520\n2.060\"",
  "tool": {
    "description": "Build a tempo map from a list of beat times: the BPM-versus-time curve of a performance rather than one global tempo. `beats` is the beat timestamps, one per line — a beat-tracker or DAW marker export, an Audacity label track, a CSV column, or tapped times; each line's first field is used, headers/blank lines/# comments are skipped, and a single comma-separated line works too. Times may be decimal seconds, unit-suffixed values (1750ms), m:ss.mmm, h:mm:ss.mmm or hh:mm:ss:ff frame timecode (`fps` sets the frame rate; `time_unit` decides whether a bare number is seconds or milliseconds). Every consecutive pair of beats gives one instantaneous tempo, so N beats yield N-1 readings. `beat_unit` converts the marked pulse to standard quarter-note BPM and fixes half/double-time readings. `smoothing` plus `smooth_method` apply a centred moving mean or median to flatten tapping jitter, `min_interval_ms` drops double taps, and `offset_seconds` aligns the map to a project timeline. `grid_seconds` resamples the curve onto an even time grid. `output` selects csv/tsv columns ready to plot, json with a summary object, an aligned table ledger, an Audacity label track, a Standard-MIDI-File tempo map (tick, microseconds per quarter, bpm at `ppq` ticks per quarter), or a statistics-only summary reporting mean/median/min/max BPM, drift, standard deviation, interval jitter, the overall average tempo, the trend in BPM per minute, a stability rating and the conventional tempo marking. Pure compute — nothing is fetched, uploaded or stored.",
    "parameters": {
      "additionalProperties": false,
      "properties": {
        "beat_unit": {
          "default": "quarter",
          "description": "The note value each supplied beat represents, used to convert the reading to standard quarter-note BPM. 'quarter' (default) is a normal beat. Use this to fix a half/double-time reading: 'half' doubles the BPM (you marked every other beat), 'eighth' halves it (you marked twice per beat). Dotted and triplet-eighth pulses are supported for compound and swung material.",
          "enum": [
            "whole",
            "dotted-half",
            "half",
            "dotted-quarter",
            "quarter",
            "dotted-eighth",
            "eighth",
            "triplet-eighth",
            "sixteenth"
          ],
          "type": "string"
        },
        "beats": {
          "description": "The beat times, one per line — a beat-tracker export, a DAW marker list, an Audacity label track, a CSV column or tapped timestamps. Each line's first field is used, so extra columns are ignored; blank lines, a header row, and # or // comments are skipped. A single comma-separated line (0, 0.5, 1) is also accepted. Times may be decimal seconds (1.75), a unit-suffixed value (1750ms), m:ss.mmm (0:01.750), h:mm:ss.mmm, or hh:mm:ss:ff frame timecode. At least 2 and at most 20000 beats; they must increase.",
          "type": "string"
        },
        "decimals": {
          "default": 2,
          "description": "Digits after the decimal point for BPM values, 0-4. Default 2. Times are always given to millisecond precision.",
          "maximum": 4,
          "minimum": 0,
          "type": "integer"
        },
        "fps": {
          "default": 30.0,
          "description": "Frame rate used only when a beat time is written as hh:mm:ss:ff frame timecode, so the last field can be converted to seconds. Common values are 24, 25, 29.97, 30 and 60. Ignored by every other time format. Default 30.",
          "maximum": 240,
          "minimum": 1,
          "type": "number"
        },
        "grid_seconds": {
          "default": 0.0,
          "description": "Resample the curve onto an even time grid instead of one row per beat: the number of seconds between rows, for example 1 for a reading every second. Each grid row holds the tempo of the beat interval it falls inside. 0 (default) emits one row per beat. Cannot be used with output=midi.",
          "maximum": 3600,
          "minimum": 0,
          "type": "number"
        },
        "min_interval_ms": {
          "default": 0.0,
          "description": "Drop any beat that lands closer than this many milliseconds to the previous kept beat — the double-tap guard for hand-tapped input, and the way to remove duplicated markers. 0 (default) keeps every beat. 80-200 suits tapping.",
          "maximum": 10000,
          "minimum": 0,
          "type": "number"
        },
        "offset_seconds": {
          "default": 0.0,
          "description": "Seconds added to every beat time before anything else, so the map lines up with a project timeline. Negative values shift earlier, for example -2.5 when your export started 2.5 s after the session start. Default 0.",
          "type": "number"
        },
        "output": {
          "default": "csv",
          "description": "Result format. 'csv' (default) and 'tsv' emit time_seconds, bpm, beat and interval_ms columns ready to plot; 'json' returns the whole map plus a summary object; 'table' is an aligned human-readable ledger with a per-beat deviation column and a statistics footer; 'audacity' emits a tab-separated label track (start, end, BPM) you can import back into a label editor; 'midi' emits Standard-MIDI-File tempo-map rows (tick, microseconds_per_quarter, bpm) with one event per tempo change; 'summary' reports only the statistics.",
          "enum": [
            "csv",
            "tsv",
            "json",
            "table",
            "audacity",
            "midi",
            "summary"
          ],
          "type": "string"
        },
        "ppq": {
          "default": 960,
          "description": "Ticks per quarter note used to place the tick column of the output=midi tempo map, 24-15360. Match your DAW or MIDI file's division — 480 and 960 are the usual values. Ignored by every other output format. Default 960.",
          "maximum": 15360,
          "minimum": 24,
          "type": "integer"
        },
        "smooth_method": {
          "default": "mean",
          "description": "How the smoothing window is combined: 'mean' (default) averages the window; 'median' takes the middle value, which ignores a single badly-placed beat instead of letting it drag the curve. Ignored when smoothing is 1.",
          "enum": [
            "mean",
            "median"
          ],
          "type": "string"
        },
        "smoothing": {
          "default": 1,
          "description": "Width, in beats, of a centred moving window applied to the tempo curve, 1-64. 1 (default) keeps every raw beat-to-beat reading; larger values flatten tapping jitter so the underlying tempo shape is readable. Try 4-8 for hand-tapped input.",
          "maximum": 64,
          "minimum": 1,
          "type": "integer"
        },
        "time_unit": {
          "default": "auto",
          "description": "How to read a plain number with no unit suffix: 'auto' (default) and 'seconds' treat it as seconds; 'milliseconds' treats it as milliseconds. Colon timecodes and explicit ms/s suffixes are always honoured whatever this is set to. Default auto.",
          "enum": [
            "auto",
            "seconds",
            "milliseconds"
          ],
          "type": "string"
        }
      },
      "required": [
        "beats"
      ],
      "type": "object"
    }
  }
}