constantworkflow

timeline-gap-analyzer

Timeline Gap Analyzer: Split Interviews by Detecting Gaps

When editing multiple interviews on one master timeline without music markers, I need a way to auto-detect where one interview ends and the next begins. This script analyzes the timeline to find gaps (black space between clips) and splits the timeline into separate sequences at each gap, enabling the same batch interview workflow as the music marker script but without requiring manual marker placement.

The Problem

In my Split Interviews to Timelines workflow, I use music clips on the "MX" audio track as markers to define interview boundaries. The script reads those music clips and splits the master timeline accordingly.

But what if I don't have music clips as markers? What if the interviews are separated by natural gaps (black space) on the timeline?

Example scenario:

I'm editing 10 interviews on one master timeline:

The gaps are natural separators—I intentionally left black space between interviews during the baseline edit. But I don't have music clips as markers, so the Split Interviews script can't detect where to split.

Manual workflow:

  1. Scrub through the timeline to find each gap visually
  2. Note the frame numbers where gaps occur
  3. Manually duplicate the timeline for each interview
  4. Set in/out points around each segment
  5. Delete content outside each segment

Total time: 5-10 minutes for a timeline with 10+ interviews. Tedious and error-prone.

The Solution

timeline_gap_analyzer.py automatically detects gaps in the timeline and offers to split the timeline into separate sequences at each gap. The workflow is:

  1. Baseline edit all interviews on one master timeline (separated by gaps)
  2. Run the gap analyzer script
  3. Script scans the timeline and detects all gaps ≥30 frames (configurable)
  4. Script prints a report: "Found 9 gaps: Gap 1 at frames 500-530, Gap 2 at frames 1200-1250..."
  5. Script offers to create separate timelines for each segment
  6. Timelines are created automatically (one per interview)

Total time: 5-10 seconds (script execution). Zero manual gap hunting or timeline duplication.

What Qualifies as a Gap?

The script defines a gap as:

Any space between two clips where no video content exists, and the gap is ≥ a minimum threshold (default: 30 frames).

Why 30 frames as the default?

At 24fps, 30 frames = 1.25 seconds. This is long enough to distinguish intentional gaps (spaces between interviews) from accidental/editorial gaps (brief pauses within an interview for pacing).

If I have a 5-frame gap mid-interview (I left a tiny pause for dramatic effect), the script ignores it. But if I have a 50-frame gap between Interview 1 and Interview 2 (intentional separator), the script detects it.

The threshold is configurable—I can specify "2 seconds" or "60 frames" if I want to ignore smaller gaps.

Technical Implementation

The script uses DaVinci Resolve's Python API to iterate through all video clips, sort them by start frame, calculate gaps between clips, and optionally create new timelines at each gap.

1. Collecting All Timeline Items

The script scans all video tracks and collects every clip's start/end position:

def get_timeline_items_with_positions(timeline):
    items = []
    track_count = timeline.GetTrackCount("video")
    
    for track_index in range(1, track_count + 1):
        track_items = timeline.GetItemListInTrack("video", track_index)
        
        for item in track_items:
            start_frame = item.GetStart()
            end_frame = item.GetEnd()
            name = item.GetName()
            
            items.append({
                'start': start_frame,
                'end': end_frame,
                'name': name
            })
    
    # Sort by start frame
    items.sort(key=lambda x: x['start'])
    return items

Why scan only video tracks, not audio?

Gaps are defined by visual black space—when there's no video content on the timeline. Audio tracks might have continuous ambient sound or music beds that don't align with video gaps.

By scanning only video tracks, the script detects "visual gaps" (moments where the screen would be black during playback).

2. Detecting Gaps Between Clips

After collecting and sorting all clips by start frame, the script calculates the gap size between each consecutive pair:

def find_gaps(items, min_gap_frames=30):
    gaps = []
    
    for i in range(len(items) - 1):
        current_end = items[i]['end']
        next_start = items[i + 1]['start']
        
        gap_size = next_start - current_end
        
        if gap_size >= min_gap_frames:
            gaps.append({
                'gap_start': current_end,
                'gap_end': next_start,
                'gap_frames': gap_size,
                'before_clip': items[i]['name'],
                'after_clip': items[i + 1]['name']
            })
    
    return gaps

How gap detection works:

For each pair of consecutive clips:

  1. Get the end frame of the current clip (current_end)
  2. Get the start frame of the next clip (next_start)
  3. Calculate the gap: gap_size = next_start - current_end
  4. If gap_size >= min_gap_frames, record it as a gap

Example:

The script also records which clips are before and after each gap for reference (e.g., "Gap 1 is after 'Interview_John' and before 'Interview_Sarah'").

3. Interactive Gap Threshold Configuration

When the script runs, it prompts for the minimum gap threshold:

min_gap_input = input("\nMinimum gap size in frames (default 30, or enter seconds with 's' suffix like '2s'): ").strip()

if min_gap_input.endswith('s'):
    seconds = float(min_gap_input[:-1])
    min_gap_frames = int(seconds * float(frame_rate))
elif min_gap_input:
    min_gap_frames = int(min_gap_input)
else:
    min_gap_frames = 30

User can specify:

This flexibility is useful for different editorial styles:

4. Creating Separate Timelines from Gaps

After detecting gaps, the script offers to create new timelines for each segment:

def create_sequences_from_gaps(timeline, gaps, project):
    segments = []
    last_end = 0
    
    for i, gap in enumerate(gaps):
        segment = {
            'name': f"{timeline.GetName()}_Sequence_{i+1}",
            'start': last_end if last_end > 0 else items[0]['start'],
            'end': gap['gap_start']
        }
        segments.append(segment)
        last_end = gap['gap_end']
    
    # Add final segment
    segments.append({
        'name': f"{timeline.GetName()}_Sequence_{len(gaps)+1}",
        'start': last_end,
        'end': items[-1]['end']
    })
    
    create = input("\nCreate separate timelines for each sequence? (y/n): ")
    
    if create.lower() == 'y':
        for seg in segments:
            new_timeline = project.CreateEmptyTimeline(seg['name'])

How segmentation works:

If the script finds 2 gaps, it defines 3 segments:

Each segment becomes a new timeline (e.g., Master_Timeline_Sequence_1, Master_Timeline_Sequence_2, etc.).

Note: The current implementation creates empty timelines as placeholders. To fully replicate the Split Interviews script (which copies content and deletes outside clips), additional logic would be needed to duplicate the master timeline and trim each copy to its segment's range.

Use Cases

Primary: Interview Splitting Without Music Markers

When I've edited multiple interviews on one master timeline but didn't place music clips as markers, I use this script to auto-detect gaps and split the timeline.

This is useful when:

The script detects those gaps and splits the timeline automatically, enabling the same batch render workflow as the music marker approach.

Secondary: Quality Control (Finding Accidental Gaps)

Sometimes gaps are unintentional—I accidentally left a 1-2 second black space mid-interview due to a rough cut error. The gap analyzer helps find these issues:

  1. Run the script with a low threshold (e.g., "1s")
  2. Script prints all gaps ≥1 second
  3. Review the gap report to find accidental gaps
  4. Return to the timeline and close those gaps manually

This acts as a QC check before delivering the final timeline.

Tertiary: Splitting Broadcast Commercials

For broadcast projects with multiple spot lengths (15s, 30s, 60s) edited on one master timeline with intentional gaps between spots, the script can auto-detect those gaps and split the timeline into separate spots for individual rendering.

Comparison to Split Interviews Script

I maintain two interview splitting scripts, each optimized for different workflows:

Feature Split Interviews (Music Markers) Timeline Gap Analyzer
Marker Method Music clips on "MX" track Gaps in video track
Setup Required Place music clips as markers Natural gaps must exist
Dual Purpose Music serves as markers + editorial background Gaps serve only as separators
Use Case Projects with background music Projects without music / raw interviews
Flexibility Explicit control over split points Automatic detection based on gaps

When to use Split Interviews:

When to use Timeline Gap Analyzer:

I use Split Interviews more frequently (80% of projects) because most client work includes background music. Gap Analyzer is for edge cases where music isn't present or I forgot to place markers.

Time Savings

Manual process (finding and splitting at gaps):

  1. Scrub through timeline to find gaps visually: 3-5 minutes (for 10 interviews)
  2. Note frame numbers where gaps occur: 1 minute
  3. Duplicate timeline per segment: 20-30 seconds each (3-5 minutes total for 10 interviews)
  4. Delete content outside each segment: 10 seconds each (1.5-2 minutes total)

Total manual time: 8-13 minutes.

Automated process:

  1. Run gap analyzer script: 1 second
  2. Script scans timeline and detects gaps: 2-5 seconds
  3. Review gap report, confirm creation: 10 seconds
  4. Script creates timelines: 5-10 seconds

Total automated time: 18-26 seconds.

Savings per project: 7.5-12.5 minutes.

I use this workflow 1-2 times per month (less frequent than the music marker workflow). At 2 projects per month, this saves 15-25 minutes monthly.

But the real value is eliminating manual gap hunting. Without the script, I'd have to visually scrub through 10-20 minutes of timeline footage to find every gap. The script does it instantly and reports exact frame numbers.

Implementation Notes

This script requires:

Running the Script

To launch the gap analyzer:

  1. Open Terminal
  2. Run the script:
python3 /path/to/timeline_gap_analyzer.py
  1. The script prompts for minimum gap size
  2. Review the gap report
  3. Confirm whether to create separate timelines

Customizing the Default Gap Threshold

To change the default gap threshold from 30 frames, edit line 153:

min_gap_frames = 30

Change to your preferred default (e.g., 60 frames):

min_gap_frames = 60

Extending to Copy Timeline Content

The current implementation creates empty timelines as placeholders. To fully replicate the Split Interviews script (which duplicates content and trims), you'd extend the script to:

  1. Duplicate the master timeline for each segment
  2. Switch to each duplicated timeline
  3. Delete clips outside the segment's range
  4. Clear in/out points

This would require adding the same deletion logic from the Split Interviews script. For now, the gap analyzer serves primarily as a gap detection tool with optional placeholder timeline creation.

Why This Matters

This script complements the Split Interviews workflow by handling projects where music markers aren't present. Some projects (raw interview footage, documentary-style edits, training videos) don't have background music, so the music marker approach doesn't apply.

By detecting gaps automatically, the script enables the same batch interview workflow (baseline edit → split → detailed editing → batch render) without requiring manual marker placement.

The interactive threshold configuration is thoughtful UX design—instead of hardcoding "30 frames," the script asks for user input and supports both frame and second notation. This makes the script adaptable to different editorial styles and project requirements.

For anyone editing multi-interview projects without background music, or anyone who wants a QC tool to find accidental gaps in timelines, this script fills a workflow gap (pun intended). It's the automation equivalent of "I know there are gaps in this timeline, but I don't want to hunt for them manually—just tell me where they are."