Documentation
¶
Overview ¶
Package gohar implements data types and algorithms to manipulate musical concepts, such as notes (A, Bb, C#...), intervals (major sitxh, perfect fifth...), chords and scales.
Index ¶
- Constants
- Variables
- func NoteName(note PitchClass) (string, error)
- func PitchesWithClasses(from, to Pitch, pcs []PitchClass) iter.Seq2[Pitch, PitchClass]
- func ScaleName(scale Scale) (string, error)
- func ScalePatternName(pattern ScalePattern) (string, error)
- type ChordPattern
- func (c ChordPattern) Add(p Pitch) ChordPattern
- func (c ChordPattern) AsIntervals() []Interval
- func (c ChordPattern) Contains(o ChordPattern) bool
- func (c ChordPattern) CountNotes() int
- func (c ChordPattern) HasAllDegrees(pitches ...Pitch) bool
- func (c ChordPattern) HasAnyDegree(pitches ...Pitch) bool
- func (c ChordPattern) HasDegree(p Pitch) bool
- func (c ChordPattern) IntoIntervals(out []Interval) ([]Interval, error)
- func (c ChordPattern) Omit(p Pitch) ChordPattern
- func (c ChordPattern) String() string
- func (c ChordPattern) Unpack() ChordPattern
- type Interval
- type Locale
- type Note
- func (n Note) DoubleFlat() Note
- func (n Note) DoubleSharp() Note
- func (n Note) Flat() Note
- func (n Note) IsEnharmonic(note Note) bool
- func (n Note) IsHigherThan(note Note) bool
- func (n Note) Name() string
- func (n Note) Octave(oct int8) Note
- func (n Note) Pitch() Pitch
- func (n Note) Sharp() Note
- func (n Note) String() string
- func (n Note) Transpose(i Interval) Note
- type Pitch
- type PitchClass
- func (p PitchClass) Alt() Pitch
- func (p PitchClass) Base() int8
- func (p PitchClass) BaseName() byte
- func (p PitchClass) ClipToPitch(target Pitch) PitchClass
- func (p PitchClass) DoubleFlat() PitchClass
- func (p PitchClass) DoubleSharp() PitchClass
- func (p PitchClass) Flat() PitchClass
- func (p PitchClass) IsEnharmonic(o PitchClass) bool
- func (p PitchClass) IsValid() bool
- func (p PitchClass) MoveBase(step int8) PitchClass
- func (p PitchClass) Pitch(oct int8) Pitch
- func (p PitchClass) Pitches(from, to Pitch) iter.Seq[Pitch]
- func (p PitchClass) Sharp() PitchClass
- func (p PitchClass) String() string
- func (p PitchClass) Transpose(i Interval) PitchClass
- func (p PitchClass) WithAlt(alt Pitch) PitchClass
- type Scale
- type ScalePattern
- func (s ScalePattern) CountNotes() int
- func (s ScalePattern) Intervals() iter.Seq[Interval]
- func (s ScalePattern) IntervalsWithDegrees(degrees []int8) iter.Seq[Interval]
- func (s ScalePattern) Mode(degree int) (ScalePattern, error)
- func (s ScalePattern) PitchClasses(root PitchClass) iter.Seq[PitchClass]
- func (s ScalePattern) PitchClassesWithDegrees(root PitchClass, degrees []int8) iter.Seq[PitchClass]
- func (s ScalePattern) Pitches(root Pitch) iter.Seq[Pitch]
Constants ¶
const ( AltSharp = "♯" AltFlat = "♭" AltNatural = "♮" AltDoubleSharp = "𝄪" AltDoubleFlat = "𝄫" )
Variables ¶
var ( ErrBufferOverflow = errors.New("buffer overflow") ErrNilBuffer = errors.New("nil buffer") ErrInvalidPitchClass = errors.New("invalid pitch class") ErrInvalidAlteration = errors.New("invalid alteration") ErrUnknownScalePattern = errors.New("unknown scale pattern") ErrInvalidDegree = errors.New("invalid degree") )
var ( IntUnisson = Interval{} IntMinorSecond = Interval{1, 1} IntMajorSecond = Interval{1, 2} IntAugmentedSecond = Interval{1, 3} IntMinorThird = Interval{2, 3} IntMajorThird = Interval{2, 4} IntDiminishedFourth = Interval{3, 4} IntPerfectFourth = Interval{3, 5} IntAugmentedFourth = Interval{3, 6} IntDiminishedFifth = Interval{4, 6} IntPerfectFifth = Interval{4, 7} IntAugmentedFifth = Interval{4, 8} IntMinorSixth = Interval{5, 8} IntMajorSixth = Interval{5, 9} IntDiminishedSeventh = Interval{6, 9} IntAugmentedSixth = Interval{5, 10} IntMinorSeventh = Interval{6, 10} IntMajorSeventh = Interval{6, 11} IntOctave = Interval{7, 12} IntMinorNinth = Interval{8, 13} IntMajorNinth = Interval{8, 14} IntAugmentedNinth = Interval{8, 15} IntMinorTenth = Interval{9, 15} IntMajorTenth = Interval{9, 16} IntPerfectEleventh = Interval{10, 17} IntAugmentedEleventh = Interval{10, 18} IntMinorThirteenth = Interval{12, 20} IntMajorThirteenth = Interval{12, 21} IntMajorFourteenth = Interval{13, 23} )
var ( LocaleFrench = Locale{ NoteNames: []string{"do", "ré", "mi", "fa", "sol", "la", "si"}, ScaleNames: map[ScalePattern]string{ ScalePatternMajor: "majeur", ScalePatternMelodicMinor: "mineur mélodique", ScalePatternHarmonicMinor: "mineur harmonique", ScalePatternHarmonicMajor: "majeur harmonique", ScalePatternDoubleHarmonicMajor: "majeur double harmonique", }, } LocaleEnglish = Locale{ NoteNames: []string{"c", "d", "e", "f", "g", "a", "b"}, ScaleNames: map[ScalePattern]string{ ScalePatternMajor: "major", ScalePatternMelodicMinor: "melodic minor", ScalePatternHarmonicMinor: "harmonic minor", ScalePatternHarmonicMajor: "harmonic major", ScalePatternDoubleHarmonicMajor: "double harmonic major", }, } CurrentLocale = &LocaleEnglish )
var ( NoteA = Note{PitchClassA, 0} NoteB = Note{PitchClassB, 0} NoteC = Note{PitchClassC, 0} NoteD = Note{PitchClassD, 0} NoteE = Note{PitchClassE, 0} NoteF = Note{PitchClassF, 0} NoteG = Note{PitchClassG, 0} )
var ( ErrCannotParseNote = errors.New("cannot parse note") ErrUnknownAlteration = errors.New("unknown alteration") )
var ErrLocaleNotSet = errors.New("gohar.CurrentLocale is not set")
Functions ¶
func NoteName ¶
func NoteName(note PitchClass) (string, error)
NoteName returns the Note's name in the current locale.
ErrLocaleNotSet is returned if the package's locale isn't set.
func PitchesWithClasses ¶ added in v0.0.5
func PitchesWithClasses(from, to Pitch, pcs []PitchClass) iter.Seq2[Pitch, PitchClass]
PitchesWithClasses iterates over all pitches in the range [from, to] that belong to given pitchclasses, in ascending order.
func ScaleName ¶
ScaleName returns the Scale's name in the current locale.
ErrLocaleNotSet is returned if the package's locale isn't set.
func ScalePatternName ¶
func ScalePatternName(pattern ScalePattern) (string, error)
ScalePatternName returns the ScalePattern's name in the current locale.
ErrLocaleNotSet is returned if the package's locale isn't set.
Types ¶
type ChordPattern ¶
type ChordPattern uint32
A chord pattern is represented bitwise as a 24-bit number. Each bit corresponds to a discrete pitch, within two 12-pitch octaves. When unpacked, a chord is preferably laid out using the first octave for the base chord (triad or tetrad) and the second octave for extensions (9th and above).
This representation keeps the chord in a format that is efficiently computable, especially for set operations such as testing whether a chord contains certain degrees or extensions, whilst remaining close to most consistent naming conventions.
const ( ChordPatternMajor ChordPattern = 0b000010010001 // Major triad (C: C E G) ChordPatternMinor ChordPattern = 0b000010001001 // Minor triad (Cm: C Eb G) ChordPatternDiminished ChordPattern = 0b000001001001 // Diminished triad (C dim: C Eb Gb) ChordPatternAugmented ChordPattern = 0b000100010001 // Augmented triad (C aug: C E G#) ChordPatternSus4 ChordPattern = 0b000010100001 // sus4 chord (Csus4: C F G) ChordPatternMajor7 ChordPattern = 0b100010010001 // Major 7 chord (CMaj7: C E G B) ChordPatternMajor7No5 ChordPattern = 0b100000010001 // Major 7 (omit 5) chord (CMaj7 No5: C E B) ChordPattern7 ChordPattern = 0b010010010001 // Dominant 7 chord (C7: C E G Bb) ChordPattern7No5 ChordPattern = 0b010000010001 // Dominant 7 (omit5) chord (C7 No5: C E Bb) ChordPatternMinor7 ChordPattern = 0b010010001001 // Minor 7 chord (Cm7: C Eb G Bb) ChordPatternMinor7No5 ChordPattern = 0b010000001001 // Minor 7 No5 chord (Cm7 No5: C Eb Bb) ChordPatternMinor7Flat5 ChordPattern = 0b010001001001 // Minor 7 b5 chord (Cm7 b5: C Eb Gb Bb) ChordPatternDiminished7 ChordPattern = 0b001001001001 // Diminished 7 chord (Cdim7: C Eb Gb Bbb) )
func (ChordPattern) Add ¶
func (c ChordPattern) Add(p Pitch) ChordPattern
Add adds a pitch to the chord. This has no effect if the pitch is already present.
func (ChordPattern) AsIntervals ¶
func (c ChordPattern) AsIntervals() []Interval
func (ChordPattern) Contains ¶
func (c ChordPattern) Contains(o ChordPattern) bool
Contains return if other is a subset of the current chord pattern.
func (ChordPattern) CountNotes ¶
func (c ChordPattern) CountNotes() int
CountNotes counts the notes in the chord.
func (ChordPattern) HasAllDegrees ¶
func (c ChordPattern) HasAllDegrees(pitches ...Pitch) bool
HasAllDegree returns true if the chord contains all of the pitches.
func (ChordPattern) HasAnyDegree ¶
func (c ChordPattern) HasAnyDegree(pitches ...Pitch) bool
HasAnyDegree returns true if the chord contains any of the pitches.
func (ChordPattern) HasDegree ¶
func (c ChordPattern) HasDegree(p Pitch) bool
HasDegree returns true if the chord contains given degree as a pitch.
func (ChordPattern) IntoIntervals ¶
func (c ChordPattern) IntoIntervals(out []Interval) ([]Interval, error)
func (ChordPattern) Omit ¶
func (c ChordPattern) Omit(p Pitch) ChordPattern
Omit removes a pitch from the chord. This has no effect if the pitch is already absent.
func (ChordPattern) String ¶
func (c ChordPattern) String() string
String returns a string representation of the chord.
func (ChordPattern) Unpack ¶
func (c ChordPattern) Unpack() ChordPattern
type Locale ¶
type Locale struct {
NoteNames []string
ScaleNames map[ScalePattern]string
}
A Locale is responsible for producing string representations that suit the user's language and culture.
func (*Locale) NoteName ¶
func (loc *Locale) NoteName(note PitchClass) (string, error)
NoteName returns the Note's name in the current locale.
func (*Locale) ScalePatternName ¶
func (loc *Locale) ScalePatternName(pattern ScalePattern) (string, error)
ScalePatternName returns the ScalePattern's name in the current locale.
type Note ¶
type Note struct {
// PitchClass is the pitch class of the note
PitchClass
// Oct transposes the note up (when Oct > 0) or down (when Oct < 0) relative to the default octave (0).
Oct int8
}
A Note is an abstract music note that can be converted to pitch.
Multiple notes can correspond to the same pitch (e.g.: E# and F). Notes that have the same pitch but different names are called "enharmonic".
func FindClosestNote ¶
FindClosestNote returns the closest note with given pitch. When a pitch corresponds to an altered note ("black key"), it is always assumed to be the flattened note above it.
func NoteWithPitch ¶
func NoteWithPitch(pc PitchClass, pitch Pitch) Note
NoteWithPitch builds a note with given base and any octaves and alterations needed so that the note has given pitch.
func (Note) DoubleSharp ¶
DoubleSharp makes the note "double sharp".
func (Note) IsEnharmonic ¶
IsEnharmonic returns true if both notes have the same pitch.
func (Note) IsHigherThan ¶
IsHigherThan returns true if the current note is higher than the argument.
type Pitch ¶
type Pitch int8
A Pitch corresponds to a distinct vibration frequency. Pitches are represented as a signed integer value in the range [-127; 128]. This range is more than enough to model a piano keyboard, whose range is contained within [-50; 50].
Pitch unit is the semitone or half-step. An octave corresponds to 12 semitones.
By convention, pitch 0 corresponds to middle C on a piano keyboard.
const ( PitchC Pitch = 0 PitchBSharp Pitch = 0 PitchDDoubleFlat Pitch = 0 PitchBDoubleSharp Pitch = 1 PitchCSharp Pitch = 1 PitchDFlat Pitch = 1 PitchCDoubleSharp Pitch = 2 PitchD Pitch = 2 PitchEDoubleFlat Pitch = 2 PitchDSharp Pitch = 3 PitchEFlat Pitch = 3 PitchDDoubleSharp Pitch = 4 PitchE Pitch = 4 PitchFFlat Pitch = 4 PitchFDoubleFlat Pitch = 4 PitchESharp Pitch = 5 PitchF Pitch = 5 PitchGDoubleFlat Pitch = 5 PitchEDoubleSharp Pitch = 6 PitchFSharp Pitch = 6 PitchGFlat Pitch = 6 PitchFDoubleSharp Pitch = 7 PitchG Pitch = 7 PitchADoubleFlat Pitch = 7 PitchGSharp Pitch = 8 PitchAFlat Pitch = 8 PitchGDoubleSharp Pitch = 9 PitchA Pitch = 9 PitchBDoubleFlat Pitch = 9 PitchASharp Pitch = 10 PitchBFlat Pitch = 10 PitchCDoubleFlat Pitch = 10 PitchADoubleSharp Pitch = 11 PitchB Pitch = 11 PitchCFlat Pitch = 11 )
const ( PitchDiffUnisson Pitch = 0 PitchDiffPerfectUnisson Pitch = 0 PitchDiffHalfStep Pitch = 1 PitchDiffSemitone Pitch = 1 PitchDiffMinorSecond Pitch = 1 PitchDiffFullStep Pitch = 2 PitchDiffTone Pitch = 2 PitchDiffMajorSecond Pitch = 2 PitchDiffDiminishedThird Pitch = 2 PitchDiffAugmentedSecond Pitch = 3 PitchDiffMinorThird Pitch = 3 PitchDiffMajorThird Pitch = 4 PitchDiffDiminishedFourth Pitch = 4 PitchDiffFourth Pitch = 5 PitchDiffPerfectFourth Pitch = 5 PitchDiffAugmentedFourth Pitch = 6 PitchDiffDiminishedFifth Pitch = 6 PitchDiffFifth Pitch = 7 PitchDiffPerfectFifth Pitch = 7 PitchDiffAugmentedFifth Pitch = 8 PitchDiffMinorSixth Pitch = 8 PitchDiffMajorSixth Pitch = 9 PitchDiffDiminishedSeventh Pitch = 9 PitchDiffMinorSeventh Pitch = 10 PitchDiffMajorSeventh Pitch = 11 PitchDiffOctave Pitch = 12 PitchDiffPerfectOctave Pitch = 12 PitchDiffMinorNinth Pitch = 13 PitchDiffMajorNinth Pitch = 14 PitchDiffAugmentedNinth Pitch = 15 PitchDiffMinorTenth Pitch = 15 PitchDiffMajorTenth Pitch = 16 PitchDiffEleventh Pitch = 17 PitchDiffPerfectEleventh Pitch = 17 PitchDiffAugmentedEleventh Pitch = 18 PitchDiffMinorThirteenth Pitch = 20 PitchDiffMajorThirteenth Pitch = 21 PitchDiffMajorFourteenth Pitch = 23 )
func ParseAlteration ¶
func ParsePitch ¶
type PitchClass ¶ added in v0.0.2
type PitchClass uint8
A PitchClass can be thought of as an "absolute" or "ideal" note; it represents all octaves of a note. In other words, it represents the class of a note's pitches.
This is the kind of construct we manipulate intuitively when we say things like: - Eb belongs to the Cm11 chord. - F# belongs to the C lydian mode.
This type is encoded as a single byte.
bit number : 7654 3 210 values: AAAA X BBB A: Alteration (4 bits) encoded as 8 + A where -2 (bb) <= A <= +2 (##). B: Base Pitch Class as a number between 0 (C) and 6 (B). X: unused
Examples:
C (natural) PitchClass: 0b10000000 (= 128) fields: AAAA BBB A: 0b1000 (= 8 + 0) -> no alteration B: 0b000 (= 0) -> C F# PitchClass: 0b10010011 (= 115) fields: AAAA BBB A: 0b1001 (= 8 + 1) -> 1 sharp B: 0b011 (= 3) -> F
const ( PitchClassC PitchClass = 0 | PitchClassNatural PitchClassD PitchClass = 1 | PitchClassNatural PitchClassE PitchClass = 2 | PitchClassNatural PitchClassF PitchClass = 3 | PitchClassNatural PitchClassG PitchClass = 4 | PitchClassNatural PitchClassA PitchClass = 5 | PitchClassNatural PitchClassB PitchClass = 6 | PitchClassNatural PitchClassNatural PitchClass = (8 + 0) << 4 )
func DefaultPitchClass ¶ added in v0.0.2
func DefaultPitchClass(p Pitch) PitchClass
DefaultPitchClass returns the default PitchClass associated with given pitch. On pitches that do not map to a base pitch class ("black keys"), it picks the base pitch class immediately above and flattens it.
func NewPitchClassFromChar ¶ added in v0.0.5
func NewPitchClassFromChar(char byte, alt Pitch) (PitchClass, error)
NewPitchClassFromChar creates a new PitchClass. ErrInvalidPitchClass is returned if char isn't in the range ['A','G']. ErrInvalidAlteration is returned if alt isn't in the range [-2,2].
func (PitchClass) Alt ¶ added in v0.0.2
func (p PitchClass) Alt() Pitch
Alt returns the alteration of this PitchClass.
func (PitchClass) Base ¶ added in v0.0.2
func (p PitchClass) Base() int8
Base returns the base as a number between 0 (C) and 6 (B)
func (PitchClass) BaseName ¶ added in v0.0.5
func (p PitchClass) BaseName() byte
BaseName returns the base pitch class as an ASCII byte in the ['A','G'] range.
func (PitchClass) ClipToPitch ¶ added in v0.0.5
func (p PitchClass) ClipToPitch(target Pitch) PitchClass
ClipToPitch changes p's alteration so that the target pitch belongs to the resulting PitchClass.
func (PitchClass) DoubleFlat ¶ added in v0.0.2
func (p PitchClass) DoubleFlat() PitchClass
DoubleFlat adds a double flat to the PitchClass.
func (PitchClass) DoubleSharp ¶ added in v0.0.2
func (p PitchClass) DoubleSharp() PitchClass
DoubleSharp adds a double sharp to the PitchClass.
func (PitchClass) Flat ¶ added in v0.0.2
func (p PitchClass) Flat() PitchClass
Flat adds one flat to the PitchClass.
func (PitchClass) IsEnharmonic ¶ added in v0.0.2
func (p PitchClass) IsEnharmonic(o PitchClass) bool
IsEnharmonic returns true if both PitchClasses map to the same pitches.
func (PitchClass) IsValid ¶ added in v0.0.2
func (p PitchClass) IsValid() bool
IsValid returns true if this pitch class has: - a base in the range [1,6], - an alt in the range [-2,+2].
func (PitchClass) MoveBase ¶ added in v0.0.5
func (p PitchClass) MoveBase(step int8) PitchClass
MoveBase moves the base pitch class by given (positive or negative) steps.
func (PitchClass) Pitch ¶ added in v0.0.2
func (p PitchClass) Pitch(oct int8) Pitch
Pitch returns the pitch of the PitchClass at given octave.
func (PitchClass) Pitches ¶ added in v0.0.2
func (p PitchClass) Pitches(from, to Pitch) iter.Seq[Pitch]
Pitches iterates over all pitches of this class in ascending order within the specified range.
func (PitchClass) Sharp ¶ added in v0.0.2
func (p PitchClass) Sharp() PitchClass
Sharp adds one sharp to the PitchClass.
func (PitchClass) String ¶ added in v0.0.2
func (p PitchClass) String() string
String returns a string representation of the PitchClass. "<invalid>" is returned if the PitchClass is invalid.
func (PitchClass) Transpose ¶ added in v0.0.2
func (p PitchClass) Transpose(i Interval) PitchClass
Transpose transposes a pitch class by given interval.
func (PitchClass) WithAlt ¶ added in v0.0.5
func (p PitchClass) WithAlt(alt Pitch) PitchClass
WithAlt applies given alteration to the PitchClass.
type Scale ¶
type Scale struct {
// Root is the root note (or the tonic) of the scale.
Root PitchClass
// Pattern is the scale's pattern.
Pattern ScalePattern
}
A Scale is the association of a root Note and a ScalePattern. This pair can be extrapolated to an ordered set of notes or pitches within an octave.
This representation allows for very efficient operation on scales, such as transposing, computing modes, or testing for inclusion.
The whole structure fits within a 64bit word.
type ScalePattern ¶
type ScalePattern uint16
A Scale pattern is represented bitwise as a 12-bit number that maps an octave. Each bit corresponds to a pitch relative to the root of the scale.
For example the major scale (e.g. C D E F G A B) has the following pattern:
pattern: 101010110101 notes: B A G FE D C
This representation allows for very efficient set operations such as testing if a note or pitch belongs to a scale, because most of these operations can be carried out as a single native bitwise instruction on most target architectures.
const ( ScalePatternMajor ScalePattern = 0b101010110101 // C D E F G A B ScalePatternMelodicMinor ScalePattern = 0b101010101101 // C D Eb F G A B ScalePatternHarmonicMinor ScalePattern = 0b100110101101 // C D Eb F G Ab B ScalePatternHarmonicMajor ScalePattern = 0b100110110101 // C D E F G Ab B ScalePatternDoubleHarmonicMajor ScalePattern = 0b100110110011 // C Db E F G Ab B )
func (ScalePattern) CountNotes ¶
func (s ScalePattern) CountNotes() int
CountNotes returns the number of notes within the ScalePattern.
func (ScalePattern) Intervals ¶ added in v0.0.2
func (s ScalePattern) Intervals() iter.Seq[Interval]
Intervals converts the scale pattern into intervals relative to the tonic. This method assumes that the scale is stepwise.
func (ScalePattern) IntervalsWithDegrees ¶ added in v0.0.5
func (s ScalePattern) IntervalsWithDegrees(degrees []int8) iter.Seq[Interval]
IntervalsWithDegrees converts the scale pattern into intervals relative to the tonic. If degrees == nil, the scale is assumed to have stepwise motion, which is suitable for most common scales in western music (heptatonic scales). Otherwise, degrees describe the absolute pitch class intervals to use.
Eg. for a major pentatonic scale (degrees are the same for minor):
// notes: C D E G A
// intervals: unisson, 2nd, 3rd, 5th, 6th
// degrees: []int8{1, 2, 3, 5, 6}
majorPentatonic := ScalePattern(0b1010010101)
majorPentatonic.AsIntervals([]int8{1,2,3,5,6})
func (ScalePattern) Mode ¶
func (s ScalePattern) Mode(degree int) (ScalePattern, error)
Mode computes the n-th mode of the ScalePattern.
ErrInvalidDegree is returned if degree is not in the range [1;s.CountNotes()].
func (ScalePattern) PitchClasses ¶ added in v0.0.2
func (s ScalePattern) PitchClasses(root PitchClass) iter.Seq[PitchClass]
PitchClasses converts the scale pattern into PitchClasses starting with given root. This method assumes that the scale is stepwise.
func (ScalePattern) PitchClassesWithDegrees ¶ added in v0.0.5
func (s ScalePattern) PitchClassesWithDegrees(root PitchClass, degrees []int8) iter.Seq[PitchClass]
PitchClassesWithDegrees converts the scale pattern into PitchClasses starting with given root. degrees have the same meaning as in [ScalePattern.AsIntervals].