QuarterTap: MIDI backing that follows a live drummer, one tap per beat [GP5 scripts + converter]

Hi everyone,

I play keyboards in a band where our drummer doesn’t use a click track. I wanted to add several MIDI backing parts without asking the band to follow a fixed playback tempo—and without continually chasing a MIDI player that had drifted ahead or behind.

I’ve been building QuarterTap, with assistance from ChatGPT: a GPScript-based alternative to the built-in MIDI File Player for this particular workflow. I’m sharing the converter, scripts and setup instructions so others can try it and help improve it.

One physical tap advances the arrangement by exactly one quarter note. The MIDI events inside that quarter keep their original relative timing.

How it works

A Python converter reads a Standard MIDI File and generates a GPScript data include. During performance, everything runs inside Gig Performer; Python isn’t running in the background.

When I tap, the script:

  1. Estimates the quarter-note duration from recent tap intervals.
  2. Selects the next quarter of MIDI events.
  3. Scales their original tick offsets to that duration and schedules them.
  4. Waits for another physical tap before advancing to the following quarter.

For example, with PPQ 480 and a 505 ms quarter, events at ticks 0, 72, 181 and 410 play at approximately 0, 75.75, 190.43 and 431.35 ms after the tap. They are not quantized to the tap.

The tap controls musical position; the tempo estimate controls spacing within that quarter. There is no continuously running playhead accumulating position drift between taps. This still depends on tapping the correct beat: a missed or extra tap changes the position by a quarter, and ordinary scheduling jitter remains.

This requires one tap per quarter throughout the backing passage, not occasional tempo correction. It doesn’t listen to the drummer or infer where the band is. In 4/4 that means four taps per bar; in 6/8 a quarter spans two eighth-note beats.

Features

  • Multitrack SMF conversion, preserving original ticks and MIDI channels, with optional track-to-channel mapping.
  • Note On/Off, CC, program change, pitch bend, channel/poly aftertouch and supported SysEx playback.
  • Notes can span quarters: a later Note Off plays when its quarter is triggered.
  • MIDI Learn for a note press, note release, CC value or another channel-voice message. Note velocity doesn’t affect matching.
  • Adjustable tempo smoothing, with an initial tempo taken from the MIDI file.
  • Reset, Panic, and bar/beat/quarter/BPM logging.
  • Song-part start positions: selecting a mapped part initializes the next position and waits for a tap.
  • GP global transpose, including the value controlled through the setlist, with configurable keyswitch ranges and whole channels excluded. Note releases remember the pitch used by their Note On.

My routing uses one multitimbral Kontakt instance. All generated MIDI goes to it; channels select the instruments. There is no separate playback block per MIDI track. Other MIDI instruments can be wired to the output, but this package’s setup is documented around Kontakt.

Download

QuarterTap_GP5_Community.zip (43.0 KB)

It contains the source scripts, Python converter, detailed guides, tests and a small synthetic MIDI fixture. It is a manual setup package, not a ready-made .gig/.rackspace or a Kontakt preset. No Kontakt libraries or personal song arrangements are included.

Quick setup

You’ll need GP5 with GPScript support, your instrument plugin(s), and Python 3.10+ for the one-time conversion step.

  1. Extract the ZIP and read README.md. Copy the .gpscript files into Documents/Gig Performer/Scripts (use your actual Documents location).

  2. Convert your arrangement from a terminal in the extracted folder:

    python -m pip install -r requirements.txt
    python midi_to_gpscript.py MySong.mid
    

    This produces MySongData.gpscript and a JSON audit report. To assign four instrument tracks to channels 1–4:

    python midi_to_gpscript.py MySong.mid --map 1:1,2:2,3:3,4:4
    

    These are zero-based file track indices. That example assumes track 0 is a conductor/metadata track. Check the converter’s inventory; files without a conductor track may need 0:1,1:2,2:3,3:4. Omit --map to preserve the original channels.

  3. In the local rackspace, create two MIDI In (OSC) blocks with GPScript handles seq_out and seq_clock, with Use in GPScript enabled. Wire only seq_out to Kontakt. Leave seq_clock completely unwired: it carries private scheduler messages. On both blocks enable Ignore global transpose and leave block Transpose at 0; scripted playback applies global transpose selectively.

  4. Give the physical keyboard/controller MIDI In block the handle seq_input, with Use in GPScript enabled. Its script intercepts the tap control and forwards other MIDI through the block’s normal settings. Remove parallel routes that would let the tap key also play an instrument.

  5. Create these widget handles: seq_tap, seq_learn, seq_reset, seq_panic (momentary buttons), seq_status (text label), and seq_part_signal (hidden linear knob). Enable Ignore variations. Full widget settings are in LEARN_SETUP.md. Do not also assign the learned control to the TAP widget using GP’s native MIDI Learn.

  6. Paste QuarterTapSequencer.gpscript into the Current Rackspace Script Editor. Keep the bundled ExampleData include for the initial fixture check, then change it to Include "MySongData.gpscript" and Compile while stopped.

  7. Set Kontakt instruments to the corresponding MIDI channels. Click Learn TAP and press your chosen key. Learning itself doesn’t advance playback. To learn a release: hold the key → click Learn → release it. Click Reset and start tapping on the quarter-note downbeats; the first tap plays quarter 0.

For CC triggers, matching includes the captured value, so values 127 and 0 of the same controller don’t both tap. Both edges of a learned key, or all values of a learned CC, are consumed on the designated input. System clock and SysEx aren’t learnable triggers. To retain a learned assignment across reloads/recompiles, copy the three values printed by Learn into SequencerConfig.gpscript.

For optional song-part positioning, install SongPartBridge.gpscript in the Global Rackspace Script Editor, fill the exact song/part names and bar/beat tables in SequencerConfig.gpscript, then enable the feature. Parts of the arrangement should use the same local rackspace. UPDATE_SETUP.md covers this and transpose exclusions. There are no manual bar-jump buttons.

Behavior to understand before trying it live

Stopping taps isn’t Panic. The triggered quarter finishes; notes whose Note Off is in a future quarter can remain held. Use this script’s Panic to cancel pending playback and silence its used channels. Reset additionally returns to the beginning. These actions can also silence live notes sharing those instrument channels.

Very early taps involve a tradeoff. By default, events already scheduled keep their deadlines, so adjacent quarters can overlap and events can arrive out of source order. An early Note Off followed by the preceding quarter’s late Note On can leave a note sounding. An optional FLUSH_ON_EARLY_TAP setting emits pending events before starting the new quarter, preserving source order at the cost of compressing the old quarter’s remaining timing. The README explains both modes.

Section changes do not chase instrument state. Selecting a mapped part cancels old events and silences notes, then waits. It doesn’t reconstruct prior CCs, program changes, keyswitches or held notes. Put the required setup events at restart points. To restart the already-selected section, select another part and return; Reset means the beginning of the file.

Status and feedback

This is a community preview. The automated suite covers conversion, generated data structure and scheduling/transpose/part/learn logic. Some GPScript function bodies are tested through a limited Python translation, which is not the GP compiler or host. GP5 compilation and audio/MIDI testing have not been independently verified in the development environment. Please start in a test rackspace and follow the included MIDI-monitor acceptance checks before using it on a gig.

I’d especially welcome reports about GP version/platform, timing at your buffer size, MIDI trigger behavior, and song-part changes. If you report an issue, please include the compiler message or a short description of the expected and actual MIDI behavior.

I hope this is useful for others who want MIDI backing to follow a band that isn’t playing to a click.

Oded Hanson

I’m always surprised what people can do with Gig Performer! :slight_smile: