Re: Quick questions on types

31 views
Skip to first unread message

Hans Höglund

unread,
Dec 7, 2014, 9:57:46 AM12/7/14
to music-sui...@googlegroups.com


On 7 dec 2014, at 14:34, Hans Höglund wrote:

Hi Carlos,

You can use Voice for this, which represents a sequence of "things" with a duration. For counterpoint, you want the "thing" to be simply a pitch, i.e. Voice Pitch. To allow rests, use Voice (Maybe Pitch). To convert to a score you can use the new Music.Score.Aligned module which allow you align such a voice at any point in time (i.e. aligned 0 0 to put its beginning at time 0, aligned 2 0.5 to put its middle at time 2 etc.)


Thanks for your feedback, I am still wrestling with how to reduce complexity and make the multitude of uses for these types more obvious to the new user.

Looking forward to the nix release.

Regards,
Hans


On 6 dec 2014, at 22:44, Carlo Nucera wrote:

Hi Hans,
I'd like to ask you an advice on the types on music-suite. As I'm
writing some program to treat counterpoints, what should be in your
opinion the type of a voice?
I mean the single line of a cantus firmus, or a fifth species
counterpoint, as something essentially monophonic but untied to
particular range consideration. What would you use?

(More in general, I feel the greatest entrance barrier to this library
is a clear explanation of the more important types it provides)

Best regards
Carlo Nucera

ps. I've completed the packaging of the music-suite in nixos. In the
next days I'll do a push request to their repo :)


Carlo Nucera

unread,
Dec 7, 2014, 4:14:07 PM12/7/14
to Hans Höglund, music-sui...@googlegroups.com
Hi Hans,
thanks for the reply. I found the module you were referring to just
before your mail, but the example was unvaluable. So, if you want I
could offer more extensive impressions on why the library is a bit
hard to learn. I think the main points are two:

1) Proliferation of similar types. When a beginner tries to write an
interval, there are:
* class IsInterval a -- in Music.Pitch.Literal.Interval.
This pattern of design is ingenious indeed, but the first time I saw
the library I began to think that whatever contains the important
informations of an Interval, is an interval. So, isInterval Int
because the Int stores the number of semitones, but some instance,
like IsInterval a => IsInterval [a], are curious at least. Is there a
use case for those?
* IntervalL -- in Music.Pitch.Literal.Interval
Ok, this should be *the interval*. It stores the number of octaves,
the diatonic and the chromatic step.
* Interval -- in Music.Pitch.Common.Interval
This one stores only the diatonic and chromatic steps, delegating the
octave difference to auxiliary functions. What relation does it have
with IntervalL. Why is this information duplicate? What are the
conversion functions between the two representations?
* type Interval a = Diff (Pitch a) -- In Music.Score.Pitch (a module I
didn't expect)
This is actually the representation which let you say `d .-. c`. When
I tried with the others, I obviously got type errors. This leads to
the second point:

2) Type errors and ambiguous type errors due to the great polymorphism
embedded in the types.
Polymorphism is a feature (look at the lens library) but it quickly
becames unusable without documentation.

I hope to contribute to these issues now that I have some free time.
It would be very helpful if you'd comment the overall structure of the
suite, which are in your opinion the most important types, and what
are they useful for.

Regarding the counterpoint, Voice (Maybe Pitch) seems perfect, but I
have this issue: let's say I'd like to keep a sort of coordinate
system, to be able to say to the user: you made some parallel fifths
between this point and this other one, and eventually marking the
errors on the music. Do you have any suggestion?

Thanks again, and best regards
Carlo Nucera
> --
> You received this message because you are subscribed to the Google Groups
> "music-suite-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to music-suite-dis...@googlegroups.com.
> To post to this group, send email to music-sui...@googlegroups.com.
> To view this discussion on the web, visit
> https://groups.google.com/d/msgid/music-suite-discuss/4DAC724A-DF34-4651-AE80-24F36263846A%40hanshoglund.se.
> For more options, visit https://groups.google.com/d/optout.

Hans Höglund

unread,
Dec 7, 2014, 6:12:28 PM12/7/14
to Carlo Nucera, music-sui...@googlegroups.com
Hi Carlo,

Thanks for your detailed feedback. I will try to give you some general comments about the design and answer your questions. You might also want to look at my FARM presentation which can be found here: http://functional-art.org/2014 and its abstract: http://tiny.cc/farm-2014-hh.

The original goal of Music Suite was to generalize music notation. As a trained composer I have been taught how to work not just with the common notions of pitch and rhythm (c sharp, quarter notes etc), but also with other systems such as enharmonic 12/tone musical set theory, quarter tones, other notions of microtonality etc. I was concerned that standard notation systems and software like Sibelius/Finale was unable to handle this richness of material, and wanted a system in which various levels of strictness could be applied to time, pitch and other musical aspects. This was obviously a very ambitious goal, and in hindsight maybe not the right thing to do at this phase in my career, but it was an important factor in the original design. I then split the library into 5 musical aspects, namely time, pitch, dynamics, articulation and parts (instrumentation, timbre etc). The idea is that the libraries define various types used to represent pitch, dynamics etc, and that these can be composed by the user. In practice we often just want to use a standard representation, which is why the preludes package was created.

As you can probably tell, the Music.Time hierarchy contains musical time structures (similar to containers, but all based on the notion of placing or orienting values in time), partly inspired by FRP, and completely separate from the other musical aspects. The goal and main challenge of the library is how to keep the aspects separate and allow the user to combine them in a useful way. Because music has so *many* aspects (at least 5, and others such as space might also be interesting to add) we might easily run into types with a lot of parameters. Imagine for example that we had a type called S used to represent a list of events with onset and offsets, and wanted to parameterize pitch, dynamics and articulation: That would give us a type signature on the form "Score StandardPitch Hertz ()" etc, which I think is to obtrusive, especially as this type will turn up quite often (compare ParsecT in parsec). The solution I adopted was to treat time structures as parametric types of kind (* -> *) and use type functions to access the aspects. Thus we can get away with only one parameter, and use constructions such as "showScorePithes :: Show (Pitch a) => Score a -> [String]".

In practice, the most important types in the current version are:

Music.Pitch.Common.Pitch – Western pitch, distinguishes between f# and gb etc.
Music.Pitch.Common.Interval – Western intervals, distinguishes d5 and A4 etc.
Music.Parts.Part – Represents a musical part, i.e. an instrument and optional subdivision (Violin I.2, Flute I, Solo Horn etc.)
Music.Dynamics.Dynamic – Represents a single dynamic level
Music.Articulation.Articulation – Represents a single musical articulation
Music.Time.Time – Represents a point in time
Music.Time.Duration – Represents the distance between two points in time (a vector in time)
Music.Time.Span – Represents two points in time (the span of a musical note for example)
Music.Time.Note – A value with an attached duration
Music.Time.Event – A value with an attached span
Music.Time.Voice – A sequential composition of notes
Music.Time.Score – A parallel composition of events
Music.Time.Behavior – A continously time-varying value (same as in FRP)
Music.Time.Reactive – A discretely time-varying value (same as in FRP)

The many similarly named constructions for things such as Pitches and Interval is a consequence of this, as we need to distinguish:
- Pitch as commonly defined in Common Practice Western Music (Interval and Pitch in Music.Pitch.Common)
- The names c, d, e, f, g etc (IsInterval and IsPitch)
- The associated pitch type of another type (Music.Score.Pitch). For example if you build up a parallel collection of voices of common pitches, their pitch type is common pitch. This is what allows you to use functions such as _8va on single notes as well as on scores.

Some problems that add to the confusing here is is that

* Interval in Music.Score is defined as Diff (Pitch a), rather than being an associated type of HasPitch together with Pitch – this could probably be changed in a future version.

* The type functions and actual types (Music.Score.Pitch vs Music.Pitch.Pitch) have the same names. A problem here is that there is no good naming convention for TFs in current Haskell, which is why I adopted the current approach (some alternatives were considered, see here: https://github.com/music-suite/music-score/issues/73)

* Of course, classes such as IsPitch, IsInverval etc should define a function from a canonical type (fromString uses String, fromRational uses Rational etc). As you pointed out, Music.Pitch.Pitch and Music.Pitch.Interval are indeed the canonical types for the overloaded names and should be used, the reason they are not are historical: music-pitch-literal was created so that music-score and music-pitch should not have to depend on each other. In retrospect this was probably a bad decision as it makes the libraries harder to overlook and requires the ugly extra IntervalL. This could also be amended in a future release.

I realize that this design makes the entry-level to the barrier quite high. Still I think there are good reasons for using as detailed types as possible in Haskell: the alternative would be to skip types altogether and go into a dynamic language (a thought that I have entertained and rejected more than once in the past years). The type juggling can be quite intricate, but when it does work out I usually find that the hard work pays off, if the type-level design and restrictions are clear enough, the functions often "write themselves".

Your interest gives me some hope that the libraries could be more useful with improved design as above and (most important), better documentation and examples and I thank you for that. Please feel free to make other suggestions on how to make them more usable.

Re: Counterpoint

I have been toying with these ideas myself. Consider working with a list of (Aligned (Voice a)), which not only gives you the voices, but also their orientation in absolute time. Thus you should be able to traverse the music vertically and check that dissonances are correctly resolved, only occur on weak beats without preparation etc. Again, understanding the difference between vectors and points (and why voices and notes are sort-of vectors) is crucial here.

All the best,
Hans

Hans Höglund

unread,
Dec 8, 2014, 11:50:32 AM12/8/14
to Carlo Nucera, music-sui...@googlegroups.com
Hi Carlo,

The many similarly named constructions for things such as Pitches and
Interval is a consequence of this, as we need to distinguish:
- Pitch as commonly defined in Common Practice Western Music (Interval
 and Pitch in Music.Pitch.Common)
- The names c, d, e, f, g etc (IsInterval and IsPitch)
- The associated pitch type of another type (Music.Score.Pitch). For
 example if you build up a parallel collection of voices of common
 pitches, their pitch type is common pitch. This is what allows you
 to use functions such as _8va on single notes as well as on scores.

Could you make a practical example on why this particular distinction
is so useful?

1, 2 vs 3:

This is what I alluded to in my previous mail. We should provide useful time abstractions such as Scores, Voices etc without forcing the user to think of pitches in Western/Classical terms. Sometimes we want fewer pitches (pentatonic systems or similar), sometimes more (quarter-tones or even using Hertz). However as long as the pitch is point-like we can implement transposition.

This is made more complicated by GHCi flattening constraints. See https://github.com/music-suite/music-docs/issues/8.

1 vs 2:

As I tried to explain before, IsPitch should really be defined in terms of Pitch etc, just as IsString is defined in terms of String. They are separate for historical reasons, fixing it would require a reshuffling of the internal package dependencies.

So why is not included in a Music.Time package? Because it's not an
aspect in the music-theoretical sense?

Not really, but historical reasons again. There used to be some nasty interdependencies between the Music.Score and Music.Time hierarchies (now resolved). As you noted, the score package is growing rather large, and I could certainly see it exploded once we reach a certain level of stability, as in

music-time
music-score
music-export-musicxml
music-export-lilypond

or something like that.


The ideal design, though complex, is imho worth the complexity for the
reasons you're explaining. So we should strive to lower the actual
complexity of the implementation.

It's a double-edged sword for sure. Again I think that nice examples and good Haddocks helps enormously (this is essentially how lens does it). Personally I often find it challenging to write the Haddocks (possibly because I know the inner workings of the library too well and have to make an effort to place myself in the position of a newcomer. Also I appreciate you pointed out the most confusing design choices in terms of names etc, as these can often be changed.

You can check it at
https://github.com/meditans/music-commentary and push directly, as I
added you as a collaborator.

Great, I'll try to look into it now and then and add comments when appropriate. Feel free to rewrite or clarify my comments.


On counterpoint.

The equivalent of writing things under the score to display errors or
information would be to use the Music.Score.Meta.Annotations module,
or do I have other possibilities? Do you have any ideas on why it is
currently broken?

It happened during a recent rewrite, I'll try to look into it and comment on the issue (https://github.com/music-suite/music-score/issues/316).

Thanks,
Hans


Hans Höglund

unread,
Dec 9, 2014, 12:31:15 PM12/9/14
to music-sui...@googlegroups.com
On 9 dec 2014, at 15:01, Hans Höglund wrote:

> Hi,
>
>>> As I tried to explain before, IsPitch should really be defined in
>>> terms of Pitch etc, just as IsString is defined in terms of
>>> String. They are separate for historical reasons, fixing it would
>>> require a reshuffling of the internal package dependencies.
>>
>> Do you feel that the library is used enough to justify the need of
>> backward compatibility, or will this issues be tackled in future? In
>> the second case, do you have a time frame in mind?
>
> I think it should be changed, but it that should probably go together with a general consideration of library layout or dependencies, so I see it happening around the release of 1.10 or later but earlier than 2.0 (I don't know how many 1.* versions we should do, but I want 2.0 to be quite stable).
>
>>> It's a double-edged sword for sure. Again I think that nice examples
>>> and good Haddocks helps enormously (this is essentially how lens does
>>> it). Personally I often find it challenging to write the Haddocks
>>> (possibly because I know the inner workings of the library too well
>>> and have to make an effort to place myself in the position of a
>>> newcomer.
>>
>> I'll be glad to Haddock the suite, if you want (better if this goes
>> with some degree of structural revision to smooth out the pain points,
>> so that we avoid double work). In this case feel free to suggest
>> modules for which I could write tentative haddock documentatation.
>
> That's great. If you browse through the module you'll find that most types and functions and some modules are commented, but there is definitely much to be done in terms of clarity and style (as well as some – hopefully few – outright errors). There is also the User Guide and miscellaneous texts sketched in music-docs/src – which is what we currently display on the home page. These two should optimally be written to work well together. There is a slightly wacky system for generating the html with included examples and links from the Markdown sources – let me know if you'd like to get that to work on your system.
>
> All in all quite a bit of work, so I absolutely agree with you that the first step is to just get basic usability right first. Your commentary could prove helpful there so please keep it coming.
>
> All the best,
> Hans
>

Reply all
Reply to author
Forward
0 new messages