SSIMuse measures data replication between symbolic-music pieces represented as binary piano rolls. It adapts the Structural Similarity Index Measure (SSIM) to music by combining note-density consistency with local note-event overlap.
The method is training-free and searches for matching material under:
- temporal displacement;
- pitch-class transposition with octave equivalence through folding; and
- uniform duration scaling with musically meaningful ratios.
This repository contains the core metric, controlled-copy evaluation, real-data source retrieval, MIDI preprocessing, and compact processed data.
Figure 1. The computation pipeline of the structural similarity term
SSIMuse.py Core SSIMuse metric and FFT-accelerated alignment
controlled_data.py Controlled-copy evaluation on 16-bar clips
real_data.py Windowed real-data source retrieval
midi_utils.py MIDI-to-piano-roll conversion
assets/ Figures used by this README
data/
├── controlled/
│ ├── POP909/ Included polyphonic and melody crops
│ └── Pop1K7/ Data-source and preparation information
└── real/
├── MPDSet29/ Included 29-query/29-source melody inputs
└── CopyrightCases40/ Included 18-query/39-source melody inputs
SSIMuse requires Python 3.10 or newer.
git clone https://github.com/Tayjsl97/SSIMuse.git
cd SSIMuse
pip install numpy scipyInstall mido only if you want to convert MIDI files directly:
pip install midoNo model weights, GPU, or training procedure are required.
The core metric accepts a NumPy array with shape:
(number_of_time_steps, number_of_MIDI_pitches)
The experiments use 128 MIDI-pitch columns, four time steps per quarter note, and 16 time steps per 4/4 bar. A positive value denotes an active note and zero denotes inactivity.
import numpy as np
from SSIMuse import SSIMuse
reference = np.load("reference.npy", allow_pickle=False)
candidate = np.load("candidate.npy", allow_pickle=False)
metric = SSIMuse(weight_power=1.0)
result = metric.score(reference, candidate)
print("Density:", result.density)
print("Structure:", result.structure)
print("SSIMuse:", result.total)The first argument is the reference. The second argument is the candidate that is scaled, shifted in time, and transposed during alignment.
The returned object contains:
| Field | Meaning |
|---|---|
density |
Note-density consistency |
structure |
Best aligned local note-event overlap |
total |
density × structure |
scale_scores |
Structural score at every tested duration ratio |
The earlier tuple interface is also available:
density, structure, total = metric.compute_ssim(reference, candidate)The following are optional arguments of the SSIMuse(...) constructor.
from SSIMuse import SSIMuse
metric = SSIMuse(
local_window_steps=16,
local_hop_steps=16,
weight_power=1.0,
time_penalty=0.5,
scale_penalty=0.125,
)local_window_steps and local_hop_steps control the local MSSIM comparison.
weight_power controls local-score aggregation. time_penalty and
scale_penalty suppress matches that require large transformations.
Use weight_power=1.0 for controlled-copy evaluation and
weight_power=0.0 for the real-data retrieval configuration.
from midi_utils import midi_to_piano_roll
roll = midi_to_piano_roll(
"song.mid",
steps_per_quarter=4,
track_index=2,
ignore_drums=True,
)track_index selects one Standard MIDI File track. If it is omitted, all
pitched tracks are merged. For exact reproduction of the 29-case experiment,
use the included aligned NPY files rather than selecting MIDI tracks again.
Run POP909 with polyphonic piano rolls:
python controlled_data.py \
--references data/controlled/POP909/reference_crops \
--mixtures data/controlled/POP909/mixture_crops \
--bars 1 2 4 8 \
--output results/pop909_controlled.jsonRun POP909 with melody piano rolls:
python controlled_data.py \
--references data/controlled/POP909/reference_crops_melody \
--mixtures data/controlled/POP909/mixture_crops_melody \
--bars 1 2 4 8 \
--output results/pop909_melody_controlled.jsonAILabs/Pop1K7 is not bundled in this repository. Download the original Pop1K7.zip from the official Zenodo record before preparing its controlled clips.
The controlled clips are 16 bars long. --bars specifies the copied excerpt
lengths and may contain any integer from 1 to 16.
The included MPDSet29 data uses matching filenames for positive pairs, for
example queries/case01.npy and sources/case01.npy.
python real_data.py \
--queries-dir data/real/MPDSet29/queries \
--sources-dir data/real/MPDSet29/sources \
--output results/mpdset29.jsonRun the included infringement subset of the 40-case copyright dataset:
python real_data.py \
--queries-dir data/real/CopyrightCases40/queries \
--sources-dir data/real/CopyrightCases40/sources \
--output results/copyright_cases40.jsonThe original data are available from the authors' music-copyright-expanded repository. The included files contain symbolic note data only; no original audio is redistributed here.
Additional files in sources/ are treated as distractor candidates. Every
query must have a same-named source so retrieval accuracy can be calculated.
SSIMuse code is released under the MIT License. See LICENSE.
Processed POP909 and BMMDet_MPDSet inputs retain their upstream attribution and license notices in their respective data directories:
