Corpora
The package ships with two example corpora.
Essen Folksong Collection
A MIDI conversion of the Essen Folksong Collection (Eck, 2024; Schaffrath, 1995), redistributed under CC BY-SA 4.0. See License for attribution requirements.
Access:
import melody_features as mf
path = mf.get_corpus_path("essen")
files = mf.get_corpus_files("essen", max_files=5)
Pearce (2018) reference corpus
903 Western traditional melodies used by Pearce for IDyOM pretraining
(Pearce, 2018). This is the default reference corpus for
get_all_features().
import melody_features as mf
print(mf.list_available_corpora())
path = mf.get_corpus_path("pearce_default_idyom")
Custom reference corpora
The bundled corpora are optional. For FANTASTIC corpus statistics and IDyOM long-term-model pretraining you can point melody-features at any directory of monophonic MIDI files.
Set Config corpus to that directory. Optionally
override just one subsystem with FantasticConfig.corpus or
IDyOMConfig.corpus (short-term IDyOM runs, models=":stm", do not use a
pretraining corpus).
import melody_features as mf
my_reference = "/path/to/my/monophonic_midis"
config = mf.Config(
corpus=my_reference,
fantastic=mf.FantasticConfig(max_ngram_order=5, phrase_gap=1.5),
idyom={
"pitch_ltm": mf.IDyOMConfig(
target_viewpoints=["cpitch"],
source_viewpoints=[("cpitch", "cpint", "cpintfref")],
ppm_order=2,
models=":ltm",
# corpus=None → uses Config.corpus (my_reference)
),
},
)
# Melodies to analyse can be a different directory from the reference corpus
results = mf.get_all_features("/path/to/melodies_to_analyse", config=config)
FANTASTIC corpus statistics follow the n-gram document-frequency model in
Müllensiefen (2009). That is step 4 of the FANTASTIC pipeline (tokenize →
count → compare to reference frequencies); see FANTASTIC workflow in
Usage. IDyOM can pretrain on the same path or a separate
IDyOMConfig.corpus.
Precomputing FANTASTIC corpus statistics
get_all_features builds corpus n-gram statistics from Config.corpus
when needed. For large corpora or repeated runs, precompute once and reuse
(same phrase_gap / n_range as your FantasticConfig):
from melody_features.corpus import (
make_corpus_stats,
load_corpus_stats,
)
from melody_features.features import get_fantastic_features, get_corpus_features
from melody_features.io.midi import load_midi
make_corpus_stats(
midi_dir="/path/to/reference_midis",
output_file="my_corpus_stats.json",
n_range=(1, 5),
phrase_gap=1.5,
)
stats = load_corpus_stats("my_corpus_stats.json")
melody = load_midi("query.mid")
fantastic = get_fantastic_features(
melody, corpus_stats=stats, phrase_gap=1.5, max_ngram_order=5
)
corpus_only = get_corpus_features(
melody, corpus_stats=stats, phrase_gap=1.5, max_ngram_order=5
)
Related helpers: compute_corpus_ngrams(),
save_corpus_stats(),
make_corpus_stats_from_json().