API reference
Collections and I/O
Collections, albums, tracks — the folder-shaped data model.
A collection is a folder tree of audio files. Every directory that
directly contains audio becomes an album (named by its path relative to
the root; files sitting in the root itself form the album "."), and
every audio file a track named by its stem. Metadata tags are deliberately
not required — the folder structure people already keep their music in is
the ground truth here; the optional [tags] extra can enrich titles later.
open_collection(root)
Scan a folder tree into a Collection (albums sorted, tracks sorted).
Source code in src/musiscape/io.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 | |
load(track, sr=22050, duration=None)
Load a track as mono float audio at sr (librosa's decoders).
Source code in src/musiscape/io.py
64 65 66 67 68 | |
Feature extraction
Per-track feature extraction — the interpretable descriptor set.
Every number here has a musicological reading: note density (plucked events
per second), brightness (spectral centroid), inharmonic texture (spectral
flatness), dynamic range, harmonic/percussive balance, estimated key
(Krumhansl–Schmuckler), pitch-class entropy, pulse clarity and tonal focus
(circular statistics via :mod:ambiscape.music), and a Schaeffer TARTYP
object profile. The set was developed on a five-album solo-harp catalogue
(57 tracks) and is meant to stay small enough to explain, not to compete
with embedding models on raw similarity.
extract_collection caches to features.json in the output folder and
runs tracks in parallel; delete the file to force re-extraction.
estimate_key(chroma_mean)
Krumhansl–Schmuckler key estimate (name, correlation).
Source code in src/musiscape/features.py
40 41 42 43 44 45 46 47 48 | |
extract_track(y, sr)
All per-track descriptors from decoded audio.
Source code in src/musiscape/features.py
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | |
extract_collection(coll, out_dir, sr=22050, duration=None, workers=4, force=False)
Extract every track (parallel, cached) → <out_dir>/features.json.
Source code in src/musiscape/features.py
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | |
load_features(path)
Read a features.json produced by :func:extract_collection.
Source code in src/musiscape/features.py
144 145 146 | |
Corpus statistics
Corpus-level statistics — what existing per-track tools don't do.
The questions answered here are about the collection: how do its albums differ (fingerprints), which tracks resemble which (similarity, landscape), how internally consistent is each album, and how tightly does each cluster in key space (a circular statistic — key centers have no linear mean).
albums_of(feats)
Album names in first-appearance order.
Source code in src/musiscape/corpus.py
15 16 17 18 19 20 | |
feature_matrix(feats)
Standardised (z-scored, log-compressed where skewed) feature matrix.
Source code in src/musiscape/corpus.py
23 24 25 26 27 28 29 | |
album_stats(feats)
Per-album mean/std/min/max of every feature, plus keys and counts.
Source code in src/musiscape/corpus.py
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
landscape(feats)
PCA of the standardised features: 2-D coords, variance, loadings.
Source code in src/musiscape/corpus.py
51 52 53 54 55 56 57 58 59 60 61 62 63 | |
similarity(feats)
Track cosine-similarity matrix + album affinity and consistency.
affinity[a][b] is the mean similarity between the tracks of albums
a and b; the diagonal (mean pairwise similarity within an album) is
its internal consistency — one instrument and one mood score high,
an eclectic album scores near zero.
Source code in src/musiscape/corpus.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
tonal_spread(feats)
Per-album concentration of tonal centers on the circle of fifths.
Source code in src/musiscape/corpus.py
95 96 97 98 99 100 101 102 | |
Categorisation
Categorisation that can explain itself.
Tracks are clustered in the standardised feature space (k-means, k chosen by silhouette unless given), and every cluster is described by the features that most distinguish it from the rest of the corpus — so a category is never just "cluster 3", it is "sparse, dark, drone-like". This is the interpretable counterpart to embedding-space clustering: fewer dimensions, weaker similarity, but every axis has a musical name.
cluster(feats, k=None, seed=0)
K-means clustering with named-feature descriptions per cluster.
Returns labels aligned with feats, the silhouette score, and for
each cluster its size, member tracks, and the three most distinguishing
features as signed z-scores (e.g. onset_rate -1.2 = far sparser
than the corpus norm).
Source code in src/musiscape/categorize.py
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | |
Figures
Overview figures: fingerprints, landscape, affinity.
Categorical album colors use a fixed, colorblind-validated order (never cycled); the affinity matrix is a blue/red diverging scale around zero. Past eight albums the palette folds — facet or filter rather than invent a ninth hue.
album_colors(names)
Stable album→color map in first-appearance order.
Source code in src/musiscape/figures.py
35 36 37 | |
fingerprints(stats, out_path, title='')
Small-multiple bars: one panel per measure, one bar per album.
Source code in src/musiscape/figures.py
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | |
landscape_plot(feats, land, out_path, title='')
PCA scatter, one color per album, direct legend.
Source code in src/musiscape/figures.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | |
affinity_plot(affinity, out_path, title='')
Album-affinity matrix, diverging around zero, values in cells.
Source code in src/musiscape/figures.py
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | |
Thumbnails & posters
Per-track visual thumbnails: a piece at a glance.
Each track becomes one card, in a choice of representations:
mel/chroma/tempo/combo— the spectrogram family (timbre & texture, harmony over time, rhythmic periodicity, all three);barcode— harmony as color: each moment's hue is its position on the circle of fifths, saturation its tonal focus, brightness its loudness;ssm— self-similarity matrix: musical form as texture (repetition blocks, sections, drone slabs);trajectory— the piece as a smoothed path through its own timbre space (MFCC PCA), colored start → end;keyscape— Sapp-style triangle: every analysis window at every time scale colored by its Krumhansl–Schmuckler key (hue = tonic on the circle of fifths, light = major, dark = minor);rhythm— Poincaré portrait of successive inter-onset intervals: metric playing collapses to points, rubato spreads into clouds;wave— Freesound-style waveform: the amplitude envelope with each moment colored by its spectral centroid (dark blue = dark timbre, red = bright), so timbre rides on the waveform itself;vinyl— the track as a tonality disc (12 o'clock = start, clockwise; hue = harmony on the circle of fifths, radius = loudness), with the Freesound-style centroid-colored waveform as the strip underneath;spiral— time-integrated energy on the Shepard helix (angle = pitch class, radius = octave): the only view that shows register;tonnetz— the harmony's path on the circle-of-fifths plane of the tonal centroid (Harte's tonnetz), colored start → end;-
arcs— Shape-of-Song-style arc diagram: repeated sections found in the self-similarity structure joined by arcs over the timeline. -
tarsom— the track's position on Schaeffer's seven morphological criteria (TARSOM: masse, timbre harmonique, grain, allure, dynamique, profil mélodique, profil de masse), each a labeled gauge with signal proxies calibrated on instrumental corpora; schaeffer— the track's sound objects on a typo-morphology (TARTYP) timeline: three mass lanes (N tonic / Y variable / X complex), facture as mark style (impulse ticks, hatched iterations, solid held blocks), with a TARTYP-grid fingerprint inset. Uses the same signal proxies and thresholds asambiscape.music.tartyp_profile.
The rhythm card carries a beat-wheel inset: onset phases on the
dominant-period circle with the pulse-clarity resultant arrow.
Albums additionally get a contact sheet, and :func:poster stacks every
track's barcode into a single collection image where albums read as color
families. Thumbnails are meant for browsing a collection visually.
barcode_rgb(C, rms)
RGB strip (n×3) from 2 Hz chroma + RMS — the barcode's colors.
Source code in src/musiscape/thumbnails.py
93 94 95 96 97 98 99 100 | |
wave_colors(y, sr, cols=1200)
Amplitude envelope + turbo-mapped spectral-centroid colors.
Source code in src/musiscape/thumbnails.py
103 104 105 106 107 108 109 110 111 112 113 | |
keyscape_rgb(C, levels=48)
Sapp-style keyscape image (levels×n×3) from 2 Hz chroma.
Source code in src/musiscape/thumbnails.py
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | |
render_track(track, color, out_path, sr=22050, note='', style='mel')
One card: the chosen representation over a waveform strip.
Source code in src/musiscape/thumbnails.py
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | |
contact_sheet(paths, out_path, cols=3)
Tile thumbnails into one album overview image.
Source code in src/musiscape/thumbnails.py
658 659 660 661 662 663 664 665 666 667 668 | |
render_collection(coll, out_dir, notes=None, workers=4, style='mel')
All thumbnails → <out_dir>/thumbnails/<album>/<track>.png
plus a contact sheet per album. notes maps (album, title) to a
short annotation (e.g. the estimated key from features.json).
Source code in src/musiscape/thumbnails.py
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 | |
poster(coll, out_dir, workers=4, strip_w=1200, strip_h=16, style='barcode')
One image for the whole collection. style="barcode" stacks every
track as a horizontal color strip; style="vinyl" lays the tracks
out as a grid of disc glyphs. Albums read as color families either
way. → <out_dir>/poster.png
Source code in src/musiscape/thumbnails.py
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | |
notes_from_features(feats)
(album, track) → "key · bpm" annotation for thumbnail title bars.
The BPM shown is the perceptually-weighted tempo estimate
(tempo_bpm, librosa's prior-based estimator, which targets the
felt beat rather than the subdivision the phase-lock peaks on);
when pulse clarity is low (R < 0.1, i.e. rubato or drifting
material) it is prefixed with ~ — a nominal tempo, not a felt
one. Falls back to pulse_bpm for older feature files.
Source code in src/musiscape/thumbnails.py
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 | |
Report
Per-collection report: one README.md that answers "what is this collection?"
Runs the full pipeline (extract → stats → landscape → similarity → tonal spread → clusters), writes the figures, and renders a markdown report with an overview table, album fingerprints, affinity, categories, and notable extremes — the file you open first when handed a folder of music.
run(coll, out_dir, workers=4, duration=None, k=None)
Full pipeline → <out_dir>/README.md (+ features.json, figures).
Source code in src/musiscape/report.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | |