The Generic Interface
Overview
Handling Intervals
The operations of the generic interface are based on intervals as the fundamental elements. Intervals can be thought of as vectors in a vector space (or more precisely: a module over integers). They can be added, subtracted, negated, and multiplied with integers. Pitches, on the other hand, can be seen as points in this space and are represented as intervals in relation to an (implicit) origin. Therefore, pitch types are mainly defined as a wrapper type Pitch{Interval}
that generically defines its arithmetic operations in terms of the corresponding interval type.
Interval types (here denoted as I
) define the following operations:
I + I
I - I
-I
I * Integer
Integer * I
sign(I)
abs(I)
The sign indicates the logical direction of the interval by musical convention (upward = positive, downward = negative), even if the interval space is multi-dimensional. Consequently, abs
ensures that an interval is neutral or upward-directed. For interval classes (which are generally undirected), the sign indicates the direction of the "shortest" class member:
julia> sign(i"P4")
1
julia> sign(i"P5") # == -i"P4"
-1
In addition to arithmetic operations, some special intervals are defined:
unison(Type{I})
/zero(Type{I})
octave(Type{I})
chromsemi(Type{I})
(a chromatic semitone, optional)isstep(I)
(optional, a predicate that test whether the interval is considered a "step")
Finally, some operations specify the relationship between intervals and interval classes:
ic(I)
: Returns the corresponding interval class.embed(IC [, octs::Int])
: Returns a canonical embedding of an interval class into interval space.intervaltype(Type{IC}) = I
intervalclasstype(Type{I}) = IC
Handling Pitches
Pitch operations generally interact with intervals (and can be derived from the interval operations):
P + I -> P
I + P -> P
P - I -> P
P - P -> I
pc(P) -> PC
embed(PC [, octaves]) -> P
Other useful functions
Besides the specific functions of the interface, pitch and interval types generally implement basic functions such as
isless
/<
isequal
/==
hash
show
(usually also specialized forPitch{I}
)
Note that the ordering of pitches is generally not unique, so isless
uses an appropriate convention for each interval type.
Generic API Reference
Here we only list the new functions that are introduced by this library, not the ones that are already defined in Base
.
Special Intervals
Pitches.unison
— Functionunison(T)
Returns the interval of a unison for interval type T
. Alias for Base.zero
. New interval types should implement Base.zero
, but user code should call unison
for better interpretability.
Pitches.octave
— Functionoctave(T, [n=1])
Returns the interval corresponding to an octave for interval type T
. For interval classes, this should return zero(T)
(a default method is provided).
If n
is specified, the octave is multiplied by n
first. This is equivalent to octave(T) * n
.
For convenience, a fallback for octave(p::T, [n])
is provided. Only octave(T)
needs to be implemented.
Pitches.chromsemi
— Functionchromsemi(I::Type)
Returns a chromatic semitone of type I
.
Pitches.isstep
— Functionisstep(p)
For diatonic intervals, indicates whether p
is a step.
Classes (Octave Equivalence)
Pitches.ic
— Functionic(i)
Returns the interval class of an interval, removing the octave
Pitches.pc
— Functionpc(p)
Return the pitch class that corresponds to p
.
Pitches.embed
— Functionembed(ic, [oct=0])
embed(pc, [oct=0])
Converts an interval class to an interval in the canonical octave, adding oct
octaves, if supplied. Also works for pitches.
Pitches.intervaltype
— Functionintervaltype(IC::Type)
Returns for an interval class type IC
the corresponding interval type. For convenience, intervaltype(ic::IC)
is also provided.
Pitches.intervalclasstype
— Functionintervalclasstype(I::Type)
Returns for an interval type I
the corresponding interval class type. For convenience, intervalclasstype(p::P)
is also provided.