tonaljs / tonal

A functional music theory library for Javascript
https://tonaljs.github.io/tonal/docs
3.78k stars 217 forks source link

VoicingDictionary discussion #230

Open danigb opened 3 years ago

danigb commented 3 years ago

The aim of this issue is to publish the first voicing package: Voicing Dictionary.

I create a new issue for this, instead of following #227 because I want to broaden the discussion. /cc @felixroos

First of all, to follow conventions of other tonal dictionaries, we don't have several dictionaries (like triads, lefthand, and all) but one dictionary with properties. I imagine something like VoiceDictionary.get("m7") and you get something like:

[
  { type: "lefthand", intervals: ["3m", "5P", "7m", "9M"] },
  { type: "lefthand", intervals: [...] },
  { type: "shell", intervals: [...] }
}

where each object is of type Voice. I think is responsibility of the user to filter voices by type, for example.

The advantage of this IMO is that makes easier to extend in the future (without breaking changes) and it's more flexible (you can decide how to query the dictionary)

And that leads to a second thing: I want to keep separated the internal structure from the external interface. We can use your data file structure or another, but we have to think better what to expose (the missing Voice type)

Again, following other modules, I imagine the API of this module to something like this:

VoiceDictionary.get() 
VoiceDictionary.all() 
VoiceDictionary.add()
VoiceDictionary.remove()

I know this is not the normal functional pattern, but I think it has the user comodity of having one (customisable) dictionary

How does it fit with your idea and with #227?

felixroos commented 3 years ago

to follow conventions of other tonal dictionaries, we don't have several dictionaries (like triads, lefthand, and all) but one dictionary with properties The advantage of this IMO is that makes easier to extend in the future (without breaking changes) and it's more flexible (you can decide how to query the dictionary)

Could not agree more, that's much better. To integrate the idea of https://github.com/tonaljs/tonal/issues/227 a dictionary entry could look like this:

{ type: "shell", intervals: [...], chords: [...] }
/* */

get could take a type string instead:

get(chord: string, type?: string)

This then filters the list and returns all entries that contain chord or an alias of chord (inside the chords property). The filtered items' intervals would then be concatted to one array.

felixroos commented 3 years ago

On second thought, I not sure about add / remove, as this always requires 2 function calls.. Using a custom set of voicings should be as easy as possible. What about:

get(chord: string, type?: string, dictionary = VoicingDictionary.all())

here, we could optionally pass an array of the VoicingDictionary format. Maybe we should also omit the type param, as it's easy as

VoicingDictionary.get('7').filter(({type}) => type === 'xxx'))

.. but now it's time for me to sleep 😴