Skip to content

WIP: Pitches, Voicings, and Lead Sheets Brainstorm#24

Draft
edwisdom wants to merge 1 commit intodevelopfrom
voicing-brainstorm
Draft

WIP: Pitches, Voicings, and Lead Sheets Brainstorm#24
edwisdom wants to merge 1 commit intodevelopfrom
voicing-brainstorm

Conversation

@edwisdom
Copy link
Owner

@edwisdom edwisdom commented Sep 6, 2020

I just wrote some types and function signatures here to get us a first-attempt at designing/planning the next big set of features per #23. This is all super speculative, and I think it's worth thinking seriously about design here, since it's non-obvious and will likely save us a lot of implementation work down the line.

Main New Types Proposed

  1. Pitch : Scientific pitch notation (i.e. a note name and an octave)
  2. ChordWithBass (I know it's a terrible name) : A chord, and a Maybe bass note
  3. Voicing : A ChordWithBass (CWB) with an associated list of pitches
  4. Progression : A list of CWBs
  5. LeadSheet : A progression, a meter, and a list of durations (one per chord in progression)

Let the brainstorming begin!

@edwisdom edwisdom added enhancement New feature or request brainstorming Idea-dumping and feedback on said idea dumps labels Sep 6, 2020
Copy link
Collaborator

@ChrisEPhifer ChrisEPhifer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all looks really great! There's definitely more brainstorming to be done; my initial review comments are more focused on immediate reactions to what you've spelled out here than trying to be overly clever about what happens going forward.

We're really close to what I would consider robust-enough-for-a-release code :) I expand on this more in the other comments, so I won't repeat myself here .

Comment on lines +7 to +8
-- | We might wanna make a type class of things convertible
-- to a frequency value. For this simple type, it's just the one field.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea! I can totally imagine a Playable or Audible typeclass (or something like that) that encapsulates stuff that can actually be played via MIDI.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! I wonder what existing Haskell music libraries exist for this piece of the puzzle -- maybe we don't have to write the complete conversion of MIDI or notes to frequencies/sounds ourselves?

Comment on lines +10 to +12
-- All of these datatypes are also places where we can return distances
-- given 2 values. For pitch, we can return 3 types of distances; for MIDI, 2;
-- for frequencies, 1.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, a typeclass can unfortunately only have one instance per type in plain ol' Haskell. We can get around this limitation a little bit by using FlexibleInstances and a couple of other language extensions, but sadly I'm not sure if we have the option to have, say, only one typeclass capturing all notions of distance.

Is there a clean way to split the notions of distance you're referring to into categories such that we'd only have one instance per type we care about? That is, are the notions of distance themselves seperable into more refined typeclasses?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could have 3 different typeclasses for each of the different distances -- for frequency it's just the difference, for MIDI it's also the difference, and for pitch, it's an extended interval.

Comment on lines +59 to +61
-- | A chord with a bass note (not the best name, but hey) that can be specified or not
data ChordWithBass = ChordWithBass {getChord :: Chord,
getBass :: Maybe Note}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, as far as the name of this type is concerned, maybe the right approach is to think about what new information we have about a Chord in this type.

The way I see it, this is the type that gives us a way to talk about chords in a particular inversion. So, maybe there's something we can take from that to turn into a more reasonable name? Maybe something like PositionedChord?

I also wonder - why do we want the bass note to be wrapped in a Maybe? I mean, every chord of this type will actually have a sensible notion of a bass note; I assume that the intended semantics for a Nothing in that field are something like "this chord is in root position"? If that's the case, I think the redundancy (between the getBass field and the Chord's root) is actually fine.

Honestly, though, as I'm writing this review, and still assuming my above assumption about intended semantics is true, I'm realizing this choice depends on what we actually want to reveal in this module. I can totally envision not exporting the getBass accessor function directly, and instead handle all the Maybes internally, only exposing stuff that makes it clear you can always get back a sensible bass note.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you just said it! We could call it Inversion! (Or ChordInversion)

I think the point of the Maybe is that it's unspecified, so when we're voice leading, we can choose to put it any position that makes for the best voice leading and we know there's no constraint. And yeah, when we actually give people the inversion, there will always a reasonable bass note.

Comment on lines +67 to +69
-- | A voicing is a chord with a bass note potentially specified, and a list of pitches.
data Voicing = Voicing {getCWB :: ChordWithBass,
getPitches :: [Pitch]}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems great; I love how simple this type ends up being with all of the thought we've put into other representations this builds on :)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! It's wild how simple yet structured this is

Comment on lines +100 to +105
-- | Given a progression, a number of beats per bar, and a list of
-- durations (in number of beats), i.e. one duration per chord in progression,
-- we can create a lead sheet datatype.
data LeadSheet = LeadSheet {getProg :: Progression,
getMeter :: Int,
getDurations :: [Int]}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing this type makes me so excited; it's elegant, easily expandable if we need more information later, and totally captures all the information we expect to be in the initial language frontend. All to say, this type is screaming "it's almost time for a release!"

On that note: We might want to consider getting this stuff done, and actually preparing for a release soon after ( this prep will take a fair amount of bookkeeping effort; checking documentation consistency, getting a README in order, confirming that public APIs are correct, etc), since we have such a huge library of stuff that's frankly already useful to people who, like us, are at the intersection of music and CS. I've personally been thinking of this project as both an effort to put together really solid Haskell libraries for representing musical ideas and an effort to provide a convenient tool (ie the language) that builds on those libraries' power. I would totally defer to your judgment on any of this, though; after all, you own the concept as far as I'm concerned :)

Copy link
Owner Author

@edwisdom edwisdom Sep 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do seem so close to a prototype!

I love the idea of getting a release ready after this -- this would've all just been a random thought without your input making it actually seem/be possible, so if you think we could be ready soon, that means a ton. I defer all decision-making about what needs to be done to be release-ready to you, since you actually know what that takes. I completely agree with the broader idea about this project as both representation of musical ideas and convenient tooling -- I also see this as a first step in structuring/reducing the state space of music production and thereby making feasible the automation of increasingly larger and more complex compositional tasks.

@ChrisEPhifer
Copy link
Collaborator

So, you probably noticed I didn't mention this PR in #26. Having thought about it a little more, I think this should actually be most of what constitutes the 0.2.0 release - what we've got now is already really solid, useful to Haskell programmers who want to work with music-theoretical ideas, and even interesting for the simple chord symbol-to-notes CLI.

Mostly I think this set of features will take a while to implement, and will go through a fair number of iterations before being polished enough for a release. The other tasks I put on the todo list of that PR are, I think, some lightweight debt we should take care of sooner rather than later, and definitely need to be taken care of before a release.

Let me know what you think :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

brainstorming Idea-dumping and feedback on said idea dumps enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants