My branch is updated, and mkInterval should actually work now...
> - I understand that you propose to represent common intervals as pair
> of chromatic and diatonic steps (d2 and A1), and remove the separate
> representation of octaves. The general notion of combining two scale
> types (with large and small steps) seem more general than just
> common/western pitch. Could we abstract this pattern out as a type
> constructor, of which Common.Interval is a specification?
I'm not sure it's the idea of *two* scale types that's general -- I
think it's the fact that the intervals are generated by a certain
number, n, of generators (akin to the number of generators of the tuning
system, and I will try to make that clear when I get started on some
tuning-related code). For common Western notation, n = 2, while e.g. for
midi, n = 1 (notes are just integers in midi).
For n > 2, some new interval names have to be invented, see for example
http://en.wikipedia.org/wiki/List_of_intervals_in_5-limit_just_intonation
and also the file FiveLimit.hs in my own AbstractMusic, where I've
fiddled around and tried to get something consistent (with n = 3)
working (it's still buggy, probably).
There's a general risk here of confusing interval *nomenclature* with
interval *tuning*, particularly if we try to generalise to non-Western
scales. We could of course represent any scale as a list of frequency
ratios, but we have to admit the possibility of the scale being tuned in
different ways, but the terminology not changing (just like in Western
music). So we would invent a datatype whose structure reflects the
interval naming system in (presumably) the language of the culture from
which the scale comes. With this two-generator A1/d2 business I think
I've found the right abstraction for Western music, but it might require
some serious thought (and maybe even linguistics!) for other
systems. Or, maybe other systems are all much simpler, and don't have
lots of pesky accidentals, who knows! I'll start looking into it.
> - I like the simplicity of your (^+^) and negateV definitions, and the
> connection to basis/linear combinations. However the definitions of
> mkInterval and extractQuality seems ad-hoc too me, though there may be
> a pattern that I am missing. Maybe this has to do with the specific
> nature of the chromatic/diatonic scales (which would imply that a
> generalization as per above could mitigate the problem).
There is a pattern if you squint a bit! The apparent ad-hocness of
extractQuality comes from the fact that the "base" intervals (Perfect,
Major, Minor) are unevenly distributed throughout the octave, so there
has to be a base case of recursion for each one -- at least the way I've
written it. Perhaps the big pattern-matching blob could be simplified
slightly, but that might make it even harder to read!
The exact way these two functions have ended up being written is
partially due to the fact that I've chosen A1/d2 as the basis
vectors. Two others could be chosen, but I think this choice gives as
neat results as we're going to get (though actually A1/m2 would probably
be "nice" too).
mkInterval just builds up the Perfect/Major/Minor intervals of the scale
step by step, then uses recursion to reduce diminished/augmented
intervals to the base cases.
The main problem here is beyond our control: expressions like "Perfect
Third" and "Major Fourth" have no meaning, and there are also
redundancies e.g. the fact that "Augmented Minor Third" === "Major
Third". As a result, datatypes like Quality (from Interval.hs) will
always be a bit tricky to define. In AbstractMusic I get around this by
requiring that the user say things like "Diminished Minor Third"
explicitly.
> - Could we use Data.Basis (from vector-space) as a general interface
> to diatonic/chromatic? I.e. the basis for Common.Interval would be a
> type (data CommonBasis = Diatonic | Chromatic) or similar.
That sounds like an interesting idea, though unfortunately I'm not
familiar with how to use Data.Basis & I couldn't find any documentation
either. Perhaps you could give some simple examples? At the bottom of
Interval.hs (in my branch) I've put a basis-conversion function
(convertBasis), which I imagine would be useful in this situation.
Edward