Skip to main content

Music theory library — notes, chords, scales, and harmonic fields

Project description

🪇 Gingo

An expressive music theory and rhythm toolkit for Python, powered by a C++17 core.

PyPI version Python 3.10+ License: MIT

From pitch classes to harmonic trees and rhythmic grids — with audio playback and a friendly CLI.

Notes, intervals, chords, scales, and harmonic fields are just the beginning: Gingo also ships with durations, tempo markings (nomes de tempo), time signatures, and sequence playback.

Português (pt-BR): https://sauloverissimo.github.io/gingo/ (guia e referência completos)


About

Gingo is a pragmatic library for analysis, composition, and teaching. It prioritizes correctness, ergonomics, and speed, while keeping the API compact and consistent across concepts.

Highlights

  • C++17 core + Python API — fast and deterministic, with full type hints.
  • Pitch & harmonyNote, Interval, Chord, Scale, Field, Tree, and Progression with identification, deduction, and comparison utilities.
  • Rhythm & timeDuration, Tempo (BPM + nomes de tempo), TimeSignature, and Sequence with note/chord events.
  • Audio.play() and .to_wav() on musical objects, plus CLI --play / --wav with waveform and strum controls.
  • CLI-first exploration — query and inspect theory concepts without leaving the terminal.


Installation

pip install gingo

Optional audio playback dependency:

pip install "gingo[audio]"

Requires Python 3.10+. Pre-built binary wheels are available for Linux, macOS, and Windows — no C++17 compiler needed. If no wheel is available for your platform, pip will build from source automatically.


Quick Start

from gingo import (
    Note, Interval, Chord, Scale, Field, Tree, ScaleType,
    Duration, Tempo, TimeSignature, Sequence,
    NoteEvent, ChordEvent, Rest,
)

# Notes
note = Note("Bb")
note.natural()      # "A#"
note.semitone()     # 10
note.frequency(4)   # 466.16 Hz
note.play(octave=4) # Listen to Bb4

# Intervals
iv = Interval("5J")
iv.semitones()      # 7
iv.anglo_saxon()    # "P5"

# Chords
chord = Chord("Cm7")
chord.root()        # Note("C")
chord.type()        # "m7"
chord.notes()       # [Note("C"), Note("Eb"), Note("G"), Note("Bb")]
chord.interval_labels()  # ["P1", "3m", "5J", "7m"]
chord.play()        # Listen to Cm7

# Identify a chord from notes
Chord.identify(["C", "E", "G"])  # Chord("CM")

# Identify a scale or field from a full note/chord set
Scale.identify(["C", "D", "E", "F", "G", "A", "B"])  # Scale("C", "major")
Field.identify(["CM", "Dm", "Em", "FM", "GM", "Am"])  # Field("C", "major")

# Deduce likely fields from partial evidence (ranked)
matches = Field.deduce(["CM", "FM"])
matches[0].field   # Field("C", "major") or Field("F", "major")
matches[0].score   # 1.0

# Compare two chords (absolute, context-free)
r = Chord("CM").compare(Chord("Am"))
r.common_notes       # [Note("C"), Note("E")]
r.root_distance      # 3
r.transformation     # "R" (neo-Riemannian Relative)
r.transposition      # -1 (not related by transposition)
r.dissonance_a       # 0.057... (psychoacoustic roughness)
r.to_dict()          # full dict serialization

# Scales
scale = Scale("C", ScaleType.Major)
[n.natural() for n in scale.notes()]  # ["C", "D", "E", "F", "G", "A", "B"]
scale.degree(5)     # Note("G")
scale.play()        # Listen to C major scale

# Harmonic fields
field = Field("C", ScaleType.Major)
[c.name() for c in field.chords()]
# ["CM", "Dm", "Em", "FM", "GM", "Am", "Bdim"]

# Compare two chords within a harmonic field (contextual)
r = field.compare(Chord("CM"), Chord("GM"))
r.degree_a           # 1 (I)
r.degree_b           # 5 (V)
r.function_a         # HarmonicFunction.Tonic
r.function_b         # HarmonicFunction.Dominant
r.root_motion        # "ascending_fifth"
r.to_dict()          # full dict serialization

# Harmonic trees (progressions and voice leading)
from gingo import Tree, Progression

tree = Tree("C", ScaleType.Major, "harmonic_tree")
tree.branches()      # All available harmonic branches
tree.paths("I")      # All progressions from tonic
tree.shortest_path("I", "V7")  # ["I", "V7"]
tree.is_valid(["IIm", "V7", "I"])  # True
tree.function("V7")  # HarmonicFunction.Dominant
tree.schemas()       # Named patterns for this tradition
tree.to_dot()        # Export to Graphviz
tree.to_mermaid()    # Export to Mermaid diagram

# Cross-tradition analysis with Progression
prog = Progression("C", "major")
prog.traditions()    # ["harmonic_tree", "jazz"]
prog.identify(["IIm", "V7", "I"])  # ProgressionMatch
prog.deduce(["IIm", "V7"])         # Ranked matches
prog.predict(["I", "IIm"])         # Suggested next chords

# Rhythm
q = Duration("quarter")
dotted = Duration("eighth", dots=1)
triplet = Duration("eighth", tuplet=3)
Tempo("Allegro").bpm()         # 140.0
Tempo(120).marking()           # "Allegretto"
TimeSignature(6, 8).classification()  # "compound"

# Sequence (events in time)
seq = Sequence(Tempo(120), TimeSignature(4, 4))
seq.add(NoteEvent(Note("C"), Duration("quarter"), octave=4))
seq.add(ChordEvent(Chord("G7"), Duration("half"), octave=4))
seq.add(Rest(Duration("quarter")))
seq.total_seconds()

# Audio
Note("C").play()
Chord("Am7").play(waveform="square")
Scale("C", "major").to_wav("c_major.wav")

CLI (quick exploration)

gingo note C#
gingo note C --fifths
gingo interval 7 --all
gingo scale "C major" --degree 5 5
gingo scale "C,D,E,F,G,A,B" --identify
gingo field "C major" --functions
gingo field "CM,FM,G7" --identify
gingo field "CM,FM" --deduce
gingo compare CM GM --field "C major"
gingo note C --play --waveform triangle
gingo chord Am7 --play --strum 0.05
gingo chord Am7 --wav am7.wav
gingo duration quarter --tempo 120
gingo tempo Allegro --all
gingo timesig 6 8 --tempo 120

Audio flags:

  • --play outputs to the system audio device
  • --wav FILE exports a WAV file
  • --waveform (sine, square, sawtooth, triangle)
  • --strum and --gap control timing between chord tones and events

Detailed Guide

Note

The Note class is the atomic unit of the library. It represents a single pitch class (C, D, E, F, G, A, B) with optional accidentals.

from gingo import Note

# Construction — accepts any common notation
c  = Note("C")      # Natural
bb = Note("Bb")     # Flat
fs = Note("F#")     # Sharp
eb = Note("E♭")     # Unicode flat
gs = Note("G##")    # Double sharp

# Core properties
bb.name()           # "Bb"   — the original input
bb.natural()        # "A#"   — canonical sharp-based form
bb.sound()          # "B"    — base letter (no accidentals)
bb.semitone()       # 10     — chromatic position (C=0, C#=1, ..., B=11)

# Frequency calculation (A4 = 440 Hz standard tuning)
Note("A").frequency(4)    # 440.0 Hz
Note("A").frequency(3)    # 220.0 Hz
Note("C").frequency(4)    # 261.63 Hz
Note("A").frequency(5)    # 880.0 Hz

# Enharmonic equivalence
Note("Bb").is_enharmonic(Note("A#"))   # True
Note("Db").is_enharmonic(Note("C#"))   # True
Note("C").is_enharmonic(Note("D"))     # False

# Equality (compares natural forms)
Note("Bb") == Note("A#")   # True — same natural form
Note("C") == Note("C")     # True
Note("C") != Note("D")     # True

# Transposition
Note("C").transpose(7)     # Note("G")  — up a perfect fifth
Note("C").transpose(12)    # Note("C")  — up an octave
Note("A").transpose(-2)    # Note("G")  — down a whole step
Note("E").transpose(1)     # Note("F")  — up a semitone

# Audio playback (requires gingo[audio])
Note("A").play(octave=4)                    # A4 (440 Hz)
Note("C").play(octave=5, waveform="square") # C5 with square wave
Note("Eb").to_wav("eb.wav", octave=4)       # Export to WAV file

# Static utilities
Note.to_natural("Bb")              # "A#"
Note.to_natural("G##")             # "A"
Note.to_natural("Bbb")             # "A"
Note.extract_root("C#m7")          # "C#"
Note.extract_root("Bbdim")         # "Bb"
Note.extract_sound("Gb")           # "G"
Note.extract_type("C#m7")          # "m7"
Note.extract_type("F#m7(b5)")      # "m7(b5)"
Note.extract_type("C")             # ""

Enharmonic Resolution Table

Gingo resolves 89 enharmonic spellings to a canonical sharp-based form:

Input Natural Category
Bb A# Standard flat
Db C# Standard flat
Eb D# Standard flat
Gb F# Standard flat
Ab G# Standard flat
E# F Special sharp (no sharp exists)
B# C Special sharp (no sharp exists)
Fb E Special flat (no flat exists)
Cb B Special flat (no flat exists)
G## A Double sharp
C## D Double sharp
E## F# Double sharp
Bbb A Double flat
Abb G Double flat
B♭ A# Unicode flat symbol
E♭♭ D Unicode double flat
♭♭G F Prefix accidentals

Interval

The Interval class represents the distance between two pitches, covering two full octaves (24 semitones).

from gingo import Interval

# Construction — from label or semitone count
p1 = Interval("P1")     # Perfect unison
m3 = Interval("3m")     # Minor third
M3 = Interval("3M")     # Major third
p5 = Interval("5J")     # Perfect fifth
m7 = Interval("7m")     # Minor seventh

# From semitone count
iv = Interval(7)         # Same as Interval("5J")

# Properties
m3.label()        # "3m"
m3.anglo_saxon()  # "mi3"
m3.semitones()    # 3
m3.degree()       # 3
m3.octave()       # 1

# Second octave intervals
b9 = Interval("b9")
b9.semitones()    # 13
b9.octave()       # 2

# Equality (by semitone distance)
Interval("P1") == Interval(0)    # True
Interval("5J") == Interval(7)    # True

All 24 Interval Labels

Semitones Label Anglo-Saxon Degree
0 P1 P1 1
1 2m mi2 2
2 2M ma2 2
3 3m mi3 3
4 3M ma3 3
5 4J P4 4
6 d5 d5 5
7 5J P5 5
8 #5 mi6 6
9 M6 ma6 6
10 7m mi7 7
11 7M ma7 7
12 8J P8 8
13 b9 mi9 9
14 9 ma9 9
15 #9 mi10 10
16 b11 ma10 10
17 11 P11 11
18 #11 d11 11
19 5 P12 12
20 b13 mi13 13
21 13 ma13 13
22 #13 mi14 14
23 bI ma14 14

Chord

The Chord class represents a musical chord — a root note plus a set of intervals from a database of 42 chord formulas.

from gingo import Chord, Note

# Construction from name
cm   = Chord("CM")           # C major
dm7  = Chord("Dm7")          # D minor seventh
bb7m = Chord("Bb7M")         # Bb major seventh
fsdim = Chord("F#dim")       # F# diminished

# Root, type, and name
cm.root()                    # Note("C")
cm.root().natural()          # "C"
cm.type()                    # "M"
cm.name()                    # "CM"

# Notes — with correct enharmonic spelling
[n.name() for n in Chord("CM").notes()]
# ["C", "E", "G"]

[n.name() for n in Chord("Am7").notes()]
# ["A", "C", "E", "G"]

[n.name() for n in Chord("Dbm7").notes()]
# ["Db", "Fb", "Ab", "Cb"]  — proper flat spelling

# Notes can also be accessed as natural (sharp-based) canonical form
[n.natural() for n in Chord("Dbm7").notes()]
# ["C#", "E", "G#", "B"]

# Interval structure
Chord("Am7").interval_labels()
# ["P1", "3m", "5J", "7m"]

Chord("CM").interval_labels()
# ["P1", "3M", "5J"]

Chord("Bdim").interval_labels()
# ["P1", "3m", "d5"]

# Size
Chord("CM").size()      # 3 (triad)
Chord("Am7").size()     # 4 (seventh chord)
Chord("G7").size()      # 4

# Contains — check if a note belongs to the chord
Chord("CM").contains(Note("E"))    # True
Chord("CM").contains(Note("F"))    # False

# Identify chord from notes (reverse lookup)
c = Chord.identify(["C", "E", "G"])
c.name()                # "CM"
c.type()                # "M"

c2 = Chord.identify(["D", "F#", "A", "C#", "E"])
c2.type()               # "9"

# Equality
Chord("CM") == Chord("CM")     # True
Chord("CM") != Chord("Cm")     # True

# Audio playback (requires gingo[audio])
Chord("Am7").play()                          # Play Am7 chord
Chord("G7").play(waveform="sawtooth")       # Custom waveform
Chord("Dm").play(strum=0.05)                 # Arpeggiated/strummed
Chord("CM").to_wav("cmajor.wav", octave=4)  # Export to WAV file

Supported Chord Types (42 formulas)

Triads (7): M, m, dim, aug, sus2, sus4, 5

Seventh chords (10): 7, m7, 7M, m7M, dim7, m7(b5), 7(b5), 7(#5), 7M(#5), sus7

Sixth chords (3): 6, m6, 6(9)

Ninth chords (4): 9, m9, M9, sus9

Extended chords (6): 11, m11, m7(11), 13, m13, M13

Altered chords (6): 7(b9), 7(#9), 7(#11), 13(#11), (b9), (b13)

Add chords (4): add9, add2, add11, add4

Other (2): sus, 7+5


Scale

The Scale class builds a scale from a tonic note and a scale pattern. It supports 10 parent families, mode names, pentatonic filters, and a chainable API.

from gingo import Scale, ScaleType, Note

# Construction — from enum, string, or mode name
s1 = Scale("C", ScaleType.Major)
s2 = Scale("C", "major")              # string form
s3 = Scale("D", "dorian")             # mode name → Major, mode 2
s4 = Scale("E", "phrygian dominant")  # mode name → HarmonicMinor, mode 5
s5 = Scale("C", "altered")            # mode name → MelodicMinor, mode 7

# Scale identity
d = Scale("D", "dorian")
d.parent()        # ScaleType.Major
d.mode_number()   # 2
d.mode_name()     # "Dorian"
d.quality()       # "minor"
d.brightness()    # 3

# Scale notes (with correct enharmonic spelling)
[n.name() for n in Scale("C", "major").notes()]
# ["C", "D", "E", "F", "G", "A", "B"]

[n.name() for n in Scale("D", "dorian").notes()]
# ["D", "E", "F", "G", "A", "B", "C"]

[n.name() for n in Scale("Gb", "major").notes()]
# ["Gb", "Ab", "Bb", "Cb", "Db", "Eb", "F"]

# Natural form (canonical sharp-based) also available
[n.natural() for n in Scale("Gb", "major").notes()]
# ["F#", "G#", "A#", "B", "C#", "D#", "F"]

# Degree access (1-indexed, supports chaining)
s = Scale("C", "major")
s.degree(1)        # Note("C")  — tonic
s.degree(5)        # Note("G")  — dominant
s.degree(5, 5)     # Note("D")  — V of V
s.degree(5, 5, 3)  # Note("F")  — III of V of V

# Walk: navigate along the scale
s.walk(1, 4)       # Note("F")  — from I, a fourth = IV
s.walk(5, 5)       # Note("D")  — from V, a fifth = II

# Modes by number or name
s.mode(2)                 # D Dorian
s.mode("lydian")          # F Lydian

# Pentatonic
s.pentatonic()                        # C major pentatonic (5 notes)
Scale("C", "major pentatonic")        # same thing
Scale("A", "minor pentatonic")        # A C D E G

# Color notes (what distinguishes this mode from a reference)
Scale("C", "dorian").colors("ionian")  # [Eb, Bb]

# Other families
Scale("C", "whole tone").size()   # 6
Scale("A", "blues").size()        # 6
Scale("C", "chromatic").size()    # 12
Scale("C", "diminished").size()   # 8

# Audio playback (requires gingo[audio])
Scale("C", "major").play()                      # Play C major scale
Scale("D", "dorian").play(waveform="triangle") # Custom waveform
Scale("A", "minor").to_wav("a_minor.wav")      # Export to WAV file

Scale Types (10 parent families)

Type Notes Pattern Description
Major 7 W-W-H-W-W-W-H Ionian mode, the most common Western scale
NaturalMinor 7 W-H-W-W-H-W-W Aeolian mode, relative minor
HarmonicMinor 7 W-H-W-W-H-A2-H Raised 7th degree, characteristic V7 chord
MelodicMinor 7 W-H-W-W-W-W-H Raised 6th and 7th degrees (ascending)
HarmonicMajor 7 W-W-H-W-H-A2-H Major with lowered 6th degree
Diminished 8 W-H-W-H-W-H-W-H Symmetric octatonic scale
WholeTone 6 W-W-W-W-W-W Symmetric whole-tone scale
Augmented 6 A2-H-A2-H-A2-H Symmetric augmented scale
Blues 6 m3-W-H-H-m3-W Minor pentatonic + blue note
Chromatic 12 H-H-H-H-H-H-H-H-H-H-H-H All 12 pitch classes

W = whole step, H = half step, A2 = augmented second, m3 = minor third


Field (Harmonic Field)

The Field class generates the diatonic chords built from each degree of a scale — the harmonic field.

from gingo import Field, ScaleType, HarmonicFunction

# Construction
f = Field("C", ScaleType.Major)

# Triads (3-note chords on each degree)
triads = f.chords()
[c.name() for c in triads]
# ["CM", "Dm", "Em", "FM", "GM", "Am", "Bdim"]
#   I     ii   iii    IV    V    vi   vii°

# Seventh chords (4-note chords on each degree)
sevenths = f.sevenths()
[c.name() for c in sevenths]
# ["CM7", "Dm7", "Em7", "FM7", "G7", "Am7", "Bm7(b5)"]
#  Imaj7  ii7   iii7  IVmaj7  V7   vi7   vii-7(b5)

# Access by degree (1-indexed)
f.chord(1)                  # Chord("CM")
f.chord(5)                  # Chord("GM")
f.seventh(5)                # Chord("G7")

# Harmonic function (Tonic / Subdominant / Dominant)
f.function(1)               # HarmonicFunction.Tonic
f.function(5)               # HarmonicFunction.Dominant
f.function(5).name          # "Dominant"
f.function(5).short         # "D"

# Role within function group
f.role(1)                   # "primary"
f.role(6)                   # "relative of I"

# Query by chord name or object
f.function("FM")            # HarmonicFunction.Subdominant
f.function("F#M")           # None (not in the field)
f.role("Am")                # "relative of I"

# Applied chords (tonicization)
f.applied("V7", 2)          # Chord("A7")  — V7 of degree II
f.applied("V7", "V")        # Chord("D7")  — V7 of degree V
f.applied("IIm7(b5)", 5)    # Chord("Am7(b5)")
f.applied(5, 2)             # Chord("A7")  — numeric shorthand

# Number of degrees
f.size()                    # 7

# Works with any scale type
f_minor = Field("A", ScaleType.HarmonicMinor)
[c.name() for c in f_minor.chords()]
# Harmonic minor field: Am, Bdim, Caug, Dm, EM, FM, G#dim

Tree (Harmonic Graph)

The Tree class represents harmonic progressions and voice leading paths within a scale's harmonic field. It requires a tradition parameter specifying which harmonic school to use.

from gingo import Tree, ScaleType, HarmonicFunction

# Construction — now requires tradition parameter
tree = Tree("C", ScaleType.Major, "harmonic_tree")

# List all available harmonic branches
branches = tree.branches()
# ["I", "IIm", "IIIm", "IV", "V7", "VIm", "VIIdim", "V7/IV", "IVm", "bVI", "bVII", ...]

# Get tradition metadata
tradition = tree.tradition()
tradition.name         # "harmonic_tree"
tradition.description  # "Alencar harmonic tree theory"

# Get named patterns (schemas)
schemas = tree.schemas()
# [Schema(name="descending", branches=["I", "V7/IIm", "IIm", "V7", "I"]), ...]

# Get all possible paths from a branch
paths = tree.paths("I")
for path in paths[:3]:
    print(f"{path.id}: {path.branch}{path.chord.name()}")
# 0: I → CM
# 1: IIm / IV → Dm
# 2: VIm → Am

# Find shortest path between two branches
path = tree.shortest_path("I", "V7")
# ["I", "V7"]

# Validate a progression
tree.is_valid(["IIm", "V7", "I"])     # True (II-V-I)
tree.is_valid(["I", "IV", "V7"])      # True
tree.is_valid(["I", "INVALID"])       # False

# Harmonic function classification
tree.function("I")       # HarmonicFunction.Tonic
tree.function("IV")      # HarmonicFunction.Subdominant
tree.function("V7")      # HarmonicFunction.Dominant

# Get all branches with a specific function
tonics = tree.branches_with_function(HarmonicFunction.Tonic)
# ["I", "VIm", ...]

# Export to visualization formats
dot = tree.to_dot(show_functions=True)
mermaid = tree.to_mermaid()

# Works with minor scales
tree_minor = Tree("A", ScaleType.NaturalMinor, "harmonic_tree")
tree_minor.branches()
# ["Im", "IIdim", "bIII", "IVm", "Vm", "bVI", "bVII", ...]

Progression (Cross-Tradition Analysis)

The Progression class coordinates harmonic analysis across multiple traditions.

from gingo import Progression

# Construction
prog = Progression("C", "major")

# List available traditions
traditions = Progression.traditions()
# [Tradition(name="harmonic_tree"), Tradition(name="jazz")]

# Get a tree for a specific tradition
tree = prog.tree("harmonic_tree")
jazz_tree = prog.tree("jazz")

# Identify tradition and schema from a progression
match = prog.identify(["IIm", "V7", "I"])
match.tradition  # "harmonic_tree"
match.schema     # "descending"
match.score      # 1.0
match.matched    # 2 (transitions)
match.total      # 2

# Deduce likely traditions from partial input
matches = prog.deduce(["IIm", "V7"], limit=5)
for m in matches:
    print(f"{m.tradition}: {m.score}")

# Predict next chords
routes = prog.predict(["I", "IIm"])
for r in routes:
    print(f"Next: {r.next} (from {r.tradition}, conf={r.confidence})")

API Reference Summary

Note

Method Returns Description
Note(name) Note Construct from any notation
.name() str Original input name
.natural() str Canonical sharp form
.sound() str Base letter only
.semitone() int Chromatic index 0-11
.frequency(octave=4) float Concert pitch in Hz
.is_enharmonic(other) bool Same pitch class?
.transpose(semitones) Note Shifted note
Note.to_natural(name) str Static: resolve spelling
Note.extract_root(name) str Static: root from chord name
Note.extract_sound(name) str Static: base letter from name
Note.extract_type(name) str Static: chord type suffix

Interval

Method Returns Description
Interval(label) Interval From label string
Interval(semitones) Interval From semitone count
.label() str Short label
.anglo_saxon() str Anglo-Saxon formal name
.semitones() int Semitone distance
.degree() int Diatonic degree number
.octave() int Octave (1 or 2)

Chord

Method Returns Description
Chord(name) Chord From chord name
.name() str Full chord name
.root() Note Root note
.type() str Quality suffix
.notes() list[Note] Chord tones (natural)
.formal_notes() list[Note] Chord tones (diatonic spelling)
.intervals() list[Interval] Interval objects
.interval_labels() list[str] Interval label strings
.size() int Number of notes
.contains(note) bool Note membership test
.compare(other) ChordComparison Detailed comparison (18 dimensions)
Chord.identify(names) Chord Static: reverse lookup

Scale

Method Returns Description
Scale(tonic, type) Scale From tonic + ScaleType/string/mode name
.tonic() Note Tonic note
.parent() ScaleType Parent family (Major, HarmonicMinor, ...)
.mode_number() int Mode number (1-7)
.mode_name() str Mode name (Ionian, Dorian, ...)
.quality() str Tonal quality ("major" / "minor")
.brightness() int Brightness (1=Locrian, 7=Lydian)
.is_pentatonic() bool Whether pentatonic filter is active
.type() ScaleType Scale type enum (backward compat, = parent)
.modality() Modality Modality enum (backward compat)
.notes() list[Note] Scale notes (natural)
.formal_notes() list[Note] Scale notes (diatonic)
.degree(*degrees) Note Chained degree: degree(5, 5) = V of V
.walk(start, *steps) Note Walk: walk(1, 4) = IV
.size() int Number of notes
.contains(note) bool Note membership
.mode(n_or_name) Scale Mode by number (int) or name (str)
.pentatonic() Scale Pentatonic version of the scale
.colors(reference) list[Note] Notes differing from a reference mode
.mask() list[int] 24-bit active positions
Scale.parse_type(name) ScaleType Static: string to enum
Scale.parse_modality(name) Modality Static: string to enum
Scale.identify(notes) Scale Static: detect scale from full note set

Field

Method Returns Description
Field(tonic, type) Field From tonic + ScaleType/string
.tonic() Note Tonic note
.scale() Scale Underlying scale
.chords() list[Chord] Triads per degree
.sevenths() list[Chord] Seventh chords per degree
.chord(degree) Chord Triad at degree N
.seventh(degree) Chord 7th chord at degree N
.applied(func, target) Chord Applied chord (tonicization)
.function(degree) HarmonicFunction Harmonic function (T/S/D)
.function(chord) HarmonicFunction? Function by chord (None if not in field)
.role(degree) str Role: "primary", "relative of I", etc.
.role(chord) str? Role by chord (None if not in field)
.compare(a, b) FieldComparison Contextual comparison (21 dimensions)
.size() int Number of degrees
Field.identify(items) Field Static: detect field from full notes/chords
Field.deduce(items, limit=10) list[FieldMatch] Static: ranked candidates from partial input

Tree

Method Returns Description
Tree(tonic, type, tradition) Tree From tonic + ScaleType/string + tradition name
.tonic() Note Tonic note
.type() ScaleType Scale type
.tradition() Tradition Tradition metadata
.branches() list[str] All harmonic branches
.paths(branch) list[HarmonicPath] All paths from a branch
.shortest_path(from, to) list[str] Shortest progression
.is_valid(branches) bool Validate progression
.schemas() list[Schema] Named patterns for this tradition
.function(branch) HarmonicFunction Harmonic function (T/S/D)
.branches_with_function(func) list[str] Branches with function
.to_dot(show_functions=False) str Graphviz DOT export
.to_mermaid() str Mermaid diagram export

Progression

Method Returns Description
Progression(tonic, type) Progression From tonic + ScaleType/string
.tonic() Note Tonic note
.type() ScaleType Scale type
Progression.traditions() list[Tradition] Static: available traditions
.tree(tradition) Tree Get tree for a tradition
.identify(branches) ProgressionMatch Identify tradition/schema
.deduce(branches, limit=10) list[ProgressionMatch] Ranked matches
.predict(branches, tradition="") list[ProgressionRoute] Suggest next chords

Tradition (struct)

Field Type Description
.name str Tradition name ("harmonic_tree", "jazz")
.description str Human-readable description

Schema (struct)

Field Type Description
.name str Pattern name ("descending", "ii-V-I")
.description str Human-readable description
.branches list[str] Branch sequence

ProgressionMatch (struct)

Field Type Description
.tradition str Matched tradition
.schema str Matched schema (or "")
.score float Match ratio (0.0–1.0)
.matched int Valid transitions
.total int Total transitions
.branches list[str] Resolved branches

ProgressionRoute (struct)

Field Type Description
.next str Suggested next branch
.tradition str From which tradition
.schema str Motivating schema (or "")
.path list[str] Complete suggested path
.confidence float Confidence (0.0–1.0)

HarmonicPath (struct)

Returned by Tree.paths(). Represents a harmonic progression step.

Field Type Description
.id int Path identifier
.branch str Target branch name
.chord Chord Resolved chord
.interval_labels list[str] Chord intervals
.note_names list[str] Chord note names

ChordComparison (struct)

Returned by Chord.compare(). Absolute (context-free) comparison of two chords.

Field Type Description
.common_notes list[Note] Notes present in both chords
.exclusive_a list[Note] Notes only in chord A
.exclusive_b list[Note] Notes only in chord B
.root_distance int Root distance in semitones (0-6, shortest arc)
.root_direction int Signed root direction (-6 to +6)
.same_quality bool Same chord type (M, m, dim, etc.)
.same_size bool Same number of notes
.common_intervals list[str] Interval labels present in both
.enharmonic bool Same pitch class set
.subset str "", "a_subset_of_b", "b_subset_of_a", "equal"
.voice_leading int Optimal voice pairing in semitones (Tymoczko 2011). -1 if different sizes
.transformation str Neo-Riemannian transformation (Cohn 2012): "", "P", "L", "R", "RP", "LP", "PL", "PR", "LR", "RL" (triads only)
.inversion bool Same notes, different root
.interval_vector_a list[int] Interval-class vector (Forte 1973): 6 elements counting ic1-6 for chord A
.interval_vector_b list[int] Interval-class vector (Forte 1973) for chord B
.same_interval_vector bool Same vector = Z-relation candidate (Forte 1973)
.transposition int Transposition index T_n (Lewin 1987): 0-11, or -1 if not related
.dissonance_a float Psychoacoustic roughness (Plomp & Levelt 1965 / Sethares 1998) for chord A
.dissonance_b float Psychoacoustic roughness (Plomp & Levelt 1965 / Sethares 1998) for chord B
Method Returns Description
.to_dict() dict Serialize all fields to a plain Python dict (Notes as strings)

FieldComparison (struct)

Returned by Field.compare(). Contextual comparison within a harmonic field.

Field Type Description
.degree_a, .degree_b int? Scale degree (None if non-diatonic)
.function_a, .function_b HarmonicFunction? Harmonic function
.role_a, .role_b str? Role within function group
.degree_distance int? Distance between degrees
.same_function bool? Same harmonic function
.relative bool Relative chord pair
.progression bool Reserved for future use
.root_motion str Diatonic root motion (Kostka & Payne): "", "ascending_fifth", "descending_fifth", "ascending_third", "descending_third", "ascending_step", "descending_step", "tritone", "unison"
.secondary_dominant str Secondary dominant (Kostka & Payne): "", "a_is_V7_of_b", "b_is_V7_of_a"
.applied_diminished str Applied diminished vii/x (Gauldin 1997): "", "a_is_viidim_of_b", "b_is_viidim_of_a"
.diatonic_a, .diatonic_b bool Belongs to the field
.borrowed_a, .borrowed_b BorrowedInfo? Modal borrowing origin
.pivot list[PivotInfo] Keys where both chords have a degree
.tritone_sub bool Tritone substitution (Kostka & Payne): both dom7, roots 6 st apart
.chromatic_mediant str Chromatic mediant (Cohn 2012): "", "upper", "lower"
.foreign_a, .foreign_b list[Note] Notes outside the scale
Method Returns Description
.to_dict() dict Serialize all fields to a plain Python dict

FieldMatch (struct)

Returned by Field.deduce(). Ranked candidate field match.

Field Type Description
.field Field Candidate field
.score float Match ratio (0.0–1.0)
.matched int Number of matched items
.total int Total items in input
.roles list[str] Roles for each item (Roman numerals)
Method Returns Description
.to_dict() dict Serialize to dict

BorrowedInfo (struct)

Field Type Description
.scale_type str Origin scale type ("NaturalMinor", etc.)
.degree int Degree in that scale
.function HarmonicFunction Function in that scale
.role str Role in that scale
Method Returns Description
.to_dict() dict Serialize to dict (function as string name)

PivotInfo (struct)

Field Type Description
.tonic str Tonic of the pivot key
.scale_type str Scale type
.degree_a int Degree of chord A in that key
.degree_b int Degree of chord B in that key
Method Returns Description
.to_dict() dict Serialize to dict

HarmonicFunction (enum)

Property Returns Description
.name str Full name: "Tonic", "Subdominant", "Dominant"
.short str Abbreviation: "T", "S", "D"

Rhythm & Time

Gingo models rhythm with first-class objects that match standard music notation.

Duration

Durations can be created by name (e.g., quarter, eighth) or as rational values. Dots and tuplets are built in.

from gingo import Duration

Duration("quarter")
Duration("eighth", dots=1)   # dotted eighth
Duration("eighth", tuplet=3) # triplet eighth
Duration(3, 16)               # 3/16

Tempo (nomos de tempo)

Tempo accepts either BPM or traditional tempo markings (nomos/nomes de tempo) such as Allegro or Adagio, and converts between them.

from gingo import Tempo, Duration

Tempo(120).marking()     # "Allegretto"
Tempo("Adagio").bpm()   # 60
Tempo("Allegro").seconds(Duration("quarter"))

Time Signature

Time signatures provide beats-per-bar, beat unit, classification, and bar duration.

from gingo import TimeSignature, Tempo

ts = TimeSignature(6, 8)
ts.classification()      # "compound"
ts.bar_duration().beats()
Tempo(120).seconds(ts.bar_duration())

Sequence & Events

Build a timeline of note/chord events with a tempo and time signature. Sequences can be transposed and played back.

from gingo import (
    Sequence, Tempo, TimeSignature, NoteEvent, ChordEvent, Rest,
    Note, Chord, Duration,
)

seq = Sequence(Tempo(96), TimeSignature(4, 4))
seq.add(NoteEvent(Note("C"), Duration("quarter"), octave=4))
seq.add(ChordEvent(Chord("G7"), Duration("half"), octave=4))
seq.add(Rest(Duration("quarter")))
seq.total_seconds()

CLI helpers for rhythm:

  • gingo duration quarter --tempo 120
  • gingo tempo Allegro --all
  • gingo timesig 6 8 --tempo 120

Audio & Playback

Any musical object can be rendered to audio with .play() or .to_wav() (monophonic synthesis). Playback uses simpleaudio when available; install the optional dependency with pip install gingo[audio] for the best cross-platform experience.

from gingo import Note, Chord, Scale

Note("C").play(waveform="sine")
Chord("Am7").play(waveform="square", strum=0.04)
Scale("C", "major").to_wav("c_major.wav", waveform="triangle")

CLI audio flags are available on note, chord, scale, and field:

  • --play outputs to speakers
  • --wav FILE exports a WAV file
  • --waveform sine|square|sawtooth|triangle
  • --strum and --gap for timing feel

Architecture

gingo/
├── cpp/                        # C++17 core library
│   ├── include/gingo/     # Public headers
│   │   ├── note.hpp           # Note class
│   │   ├── interval.hpp       # Interval class
│   │   ├── chord.hpp          # Chord class (42 formulas)
│   │   ├── scale.hpp          # Scale class (10 families, modes, pentatonic)
│   │   ├── field.hpp          # Harmonic field
│   │   ├── tree.hpp           # Harmonic tree (beta)
│   │   ├── duration.hpp       # Duration class (rhythm)
│   │   ├── tempo.hpp          # Tempo class (BPM + markings)
│   │   ├── time_signature.hpp # TimeSignature class
│   │   ├── event.hpp          # NoteEvent, ChordEvent, Rest
│   │   ├── sequence.hpp       # Sequence class (timeline)
│   │   ├── gingo.hpp          # Umbrella include
│   │   └── internal/          # Internal infrastructure
│   │       ├── types.hpp      # TypeElement, TypeVector, TypeTable
│   │       ├── table.hpp      # Lookup table class
│   │       ├── data_ops.hpp   # rotate, spread, spin operations
│   │       ├── notation_utils.hpp  # Formal notation helpers
│   │       ├── lookup_data.hpp     # Singleton with all music data
│   │       ├── lookup_progression.hpp  # Singleton with tradition data
│   │       └── mode_data.hpp       # Mode metadata
│   └── src/                   # All implementations
├── bindings/
│   └── pybind_module.cpp      # pybind11 Python bridge
├── python/gingo/
│   ├── __init__.py            # Public API re-exports
│   ├── __init__.pyi           # Type stubs (PEP 561)
│   ├── __main__.py            # CLI entry point
│   ├── audio.py               # Audio playback (requires simpleaudio)
│   └── py.typed               # PEP 561 marker
├── tests/
│   ├── cpp/                   # Catch2 test suite
│   └── python/                # pytest suite
├── CMakeLists.txt             # CMake build system
├── pyproject.toml             # scikit-build-core packaging
├── MANIFEST.in                # Source distribution manifest
└── .github/workflows/
    ├── ci.yml                 # Cross-platform CI
    └── publish.yml            # PyPI publishing via cibuildwheel

Design decisions:

  • C++ core — All music theory computation runs in compiled C++17 for performance. This is critical for real-time MIDI, FFT, and machine learning workloads.
  • pybind11 bridge — Exposes the C++ types to Python with zero-copy where possible and full type stub support for IDE autocompletion.
  • Lazy computation — Chord notes, scale notes, and formal spellings are computed on first access and cached internally using mutable fields.
  • Meyer's singleton — All lookup data (enharmonic maps, chord formulas, scale masks) is initialized once on first use, with no manual setup required.
  • Domain types over generic tables — Instead of the original generic Table data structure, the new API uses dedicated Note, Interval, Chord, Scale, and Field types with clear, discoverable methods.

Building from Source

Python package

pip install -v .

This triggers scikit-build-core, which runs CMake, compiles the C++ core, links the pybind11 module, and installs the Python package.

C++ only

cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build

C++ with tests

cmake -B build -DGINGO_BUILD_TESTS=ON
cmake --build build
cd build && ctest --output-on-failure

Run Python tests

pip install -v ".[test]"
pytest tests/python -v

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run both C++ and Python test suites
  5. Submit a pull request

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gingo-1.0.2.tar.gz (194.1 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

gingo-1.0.2-cp313-cp313-win_amd64.whl (456.5 kB view details)

Uploaded CPython 3.13Windows x86-64

gingo-1.0.2-cp313-cp313-win32.whl (407.5 kB view details)

Uploaded CPython 3.13Windows x86

gingo-1.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (620.7 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

gingo-1.0.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl (636.0 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ i686

gingo-1.0.2-cp313-cp313-macosx_11_0_arm64.whl (487.8 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

gingo-1.0.2-cp312-cp312-win_amd64.whl (456.4 kB view details)

Uploaded CPython 3.12Windows x86-64

gingo-1.0.2-cp312-cp312-win32.whl (407.5 kB view details)

Uploaded CPython 3.12Windows x86

gingo-1.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (620.2 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

gingo-1.0.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl (636.5 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ i686

gingo-1.0.2-cp312-cp312-macosx_11_0_arm64.whl (487.7 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

gingo-1.0.2-cp311-cp311-win_amd64.whl (455.4 kB view details)

Uploaded CPython 3.11Windows x86-64

gingo-1.0.2-cp311-cp311-win32.whl (407.1 kB view details)

Uploaded CPython 3.11Windows x86

gingo-1.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (621.4 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

gingo-1.0.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl (634.1 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ i686

gingo-1.0.2-cp311-cp311-macosx_11_0_arm64.whl (485.4 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

gingo-1.0.2-cp310-cp310-win_amd64.whl (454.8 kB view details)

Uploaded CPython 3.10Windows x86-64

gingo-1.0.2-cp310-cp310-win32.whl (406.6 kB view details)

Uploaded CPython 3.10Windows x86

gingo-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (620.2 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

gingo-1.0.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl (633.6 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ i686

gingo-1.0.2-cp310-cp310-macosx_11_0_arm64.whl (484.1 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

File details

Details for the file gingo-1.0.2.tar.gz.

File metadata

  • Download URL: gingo-1.0.2.tar.gz
  • Upload date:
  • Size: 194.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gingo-1.0.2.tar.gz
Algorithm Hash digest
SHA256 3cee3f048d28b13c942cdb537298e2a41b5a8e89bcb653622e2dc0c68503c282
MD5 9c8545bcee13da9e3f05079b7e5dc80e
BLAKE2b-256 3f6fc84a2d1389e7bf3352bfbbfeff31d0ff2cfbabc6a08c6db58d1bfd82e874

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: gingo-1.0.2-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 456.5 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gingo-1.0.2-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 39089c544fe3a75deafb83fe9c436a7aff11951d9f32ea1bb150615c66267f01
MD5 108e0e34f2458f935a831d1db864bb02
BLAKE2b-256 0fe40fda3bab9190316322e45831665cce49d3f886f3498fb6431ba343782701

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp313-cp313-win32.whl.

File metadata

  • Download URL: gingo-1.0.2-cp313-cp313-win32.whl
  • Upload date:
  • Size: 407.5 kB
  • Tags: CPython 3.13, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gingo-1.0.2-cp313-cp313-win32.whl
Algorithm Hash digest
SHA256 fc93383799693954e6abf4b9ad27bb79dcf4fe6c7807446b4bb71e6d4f04faa7
MD5 98201a063048ec8153890a2b4bac0931
BLAKE2b-256 906842b5a8f8f64ee199fbabe5da9721fc583b73105ecda14a0b513fc5fc9263

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c9779ec44c0e5b35bb6af3345e03dad7569e843db876482d681e5046b8cf18d4
MD5 dc07dafc78a2240dabb3723421891127
BLAKE2b-256 064c8cc36f0eb6419e5ff44e1baf2359457b861191c12202ff6c80329b28a2e4

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 c6745415a6a58711933df89a248f69f73d75ebfbcad4c0f6073405e5c71c8741
MD5 88a95ce4d136332eb37812de9412d411
BLAKE2b-256 9c43ce2627afd9a27ae99bb573983ef417076b5b1a2c203de4187e23b2b316e9

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0ca5d4975b5392923fe679bef38b6c56d42987724d6961780fef9b3c684b4d47
MD5 d629b1121ac7299e621cab70bb64b368
BLAKE2b-256 61014af25c7f0c4777a11bb86061cfb79021a34b231acc5b0ee9db04cdb41327

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: gingo-1.0.2-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 456.4 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gingo-1.0.2-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 db6c386db12499c2ff86a80210088c643c4e692d9b3f891810f47626adafc3c3
MD5 cfced4fb475e6331575218afd2a43691
BLAKE2b-256 d6f5ea633669a708787fcd4304832dca0938234e75ba5f00b2070f0fcbbb8385

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp312-cp312-win32.whl.

File metadata

  • Download URL: gingo-1.0.2-cp312-cp312-win32.whl
  • Upload date:
  • Size: 407.5 kB
  • Tags: CPython 3.12, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gingo-1.0.2-cp312-cp312-win32.whl
Algorithm Hash digest
SHA256 08c7a0a7a21e7f402915d60a3d8b463560fd9e4854b1d77d7fd4f02f54f221e4
MD5 ba97da85b91be8f9dceff6f1b4b06c91
BLAKE2b-256 e622758d1ad065943358c5a5f71fb3794cb1c9d7c8c8a213271be4ef38531ebd

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a07e52a419922434b9f8d0cacd9d9d6fa54f45533b7244e864574e7fd5059a6b
MD5 05494397524c35b19703a7e76446ad0c
BLAKE2b-256 b9bd0251aca8cf177a55b992e8a312c1e05f915c2e8ce0e648d4ca3ec1e4ce87

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 58cb55f423c4c9abe8249c8d7f187427e2744189cf3718106088aac288090c6a
MD5 55ad02eb50314bd1e3aec3c684a9ba4a
BLAKE2b-256 e48806721d9704bfdceec272bc761bb6001f0aba46c8f7396cb1c7f2c777aeac

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 940f63026b61db0aa3c459eaa84665d6002eab9f37c9d890af80609379331206
MD5 f5c69bc788a3493003d54be2c9af5cf3
BLAKE2b-256 e7de516a3ea9cc589c2ac1ea396db6bd5db5aabc0d2dd8ac5a892c6c312f6667

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: gingo-1.0.2-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 455.4 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gingo-1.0.2-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 c7cc2fe629fca6767f0ae12fe4a0769d6ae089af6e08763b832b1d2e27b9004c
MD5 4c45807ac7375e134613b98c4a1cccf2
BLAKE2b-256 2d70b945861883e94b827e75a0374e11dc4c0ba998982ca72a8b26d3a0f09c2a

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp311-cp311-win32.whl.

File metadata

  • Download URL: gingo-1.0.2-cp311-cp311-win32.whl
  • Upload date:
  • Size: 407.1 kB
  • Tags: CPython 3.11, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gingo-1.0.2-cp311-cp311-win32.whl
Algorithm Hash digest
SHA256 784bde0704ad948de67bd00fdace390edde0755f19c9e5e7f578b11e604a322e
MD5 7f4fd9efbfed20eea985ba7fedca752b
BLAKE2b-256 f2cba85ab84c517dba18fb577e4013907645bbc6d7ced84ae6fdfb2714fa1812

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a4ee15cea3b3be1bf92fab022b746d781f2186b628dbf51a1cae34117694b3e5
MD5 c413a5e58a68ac1aa7863f08ad45e16c
BLAKE2b-256 390c945c5001c7483f8cbdf563d1ed3bfcf54291112c6eb56fc8b5d9b0abae78

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 00ab523ed3b1376db5feb5bbeeff744c9ca4c8f2b411a623db0bdd0e4a674819
MD5 f7e55766c4778ebbd9e85658a036df4b
BLAKE2b-256 da0e8f92dfc2b213eb6f99cafbfc94f6aa4af8c451b7adcbffaf07b7fc299164

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9f5e39103a30e4dd1ffe77e1d0a94fad8edc011e83fb46e81549986ce1d62aa6
MD5 e7c482a940b0ba5fc59de481af6d3a6e
BLAKE2b-256 5967b94e4e045df9aa46445afea42cf79babd9e6fb6027fedbfd0b68510ff348

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: gingo-1.0.2-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 454.8 kB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gingo-1.0.2-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 dc0b7360408e49b7969e60df0b1e42e88b57ab7d0211d66051b45be9d1928d4a
MD5 8bf17a866b2b9480db8588833d073a96
BLAKE2b-256 11d7a63a075dadb45e5b8a3d7605c6e85613326f4c5a768192c9afecc92f3871

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp310-cp310-win32.whl.

File metadata

  • Download URL: gingo-1.0.2-cp310-cp310-win32.whl
  • Upload date:
  • Size: 406.6 kB
  • Tags: CPython 3.10, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gingo-1.0.2-cp310-cp310-win32.whl
Algorithm Hash digest
SHA256 c615dfc626f7de3b7eb9c7c1c29e5d63be67e876b0dd138f9415d71097dafbac
MD5 ad38dc0e6e30c3b728f6a8bb92db259c
BLAKE2b-256 7931cba388d59bfa82f8498d6a449f6c1ecd2c6274b73fcaa65981f515d2744d

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a36016fba74d5e28e8f4946c5d561d865ec986eccf59f1df918e27be511cee62
MD5 b2985ab60d7232eb93b7f8f6388921bf
BLAKE2b-256 fc48deba54f8e4414c6fdd33925cf6af6d7d22386e31a996fed8c835144ec5ae

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 539db7ad6f52dccd4b0755a09537550988ccbf1a79bcf51e87df37cfab875ce7
MD5 519b7ea4ed1e093ccd16efd4bfc7868f
BLAKE2b-256 f5e2042640e82c32c50aecfa2c479cf91836f38575f06ff6de60fb294a20fab6

See more details on using hashes here.

File details

Details for the file gingo-1.0.2-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for gingo-1.0.2-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0a0a766aa6e70cd1e60a50d073f9971bd09de189d252b551ff70bbe3add4e0b6
MD5 7135398aa4ccf6b724051754d9ff3052
BLAKE2b-256 39cf11cd1bad9e7a60f876558863ad1d5290cb8537761b034d2473a7e81a34d2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page