-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Voicing Package #224
Voicing Package #224
Conversation
Thanks a lot for both for #223 and this ❤️ . I'll read and review in depth this weekend. Meanwhile, in a quick pass I've seen:
It would be nice if you can add missing features while waiting 😇 Thanks again! |
By the way, I agree that enharmonicEquivalent should be inside Note module (or at least, not here), so maybe we can start with a smaller PR with that change. Also, I have to say that I was surprised that wasn't the actual behaviour of the For example, you can do this: Note.enharmonic('B#4') // => 'C5' But unfortunately, not this: Note.enharmonic('F2') // => 'F2' So I guess if it is just better to modify Something like you did: Of course, it should still work with pitch classes: And I guess something like What do you think? Makes sense? Is this enough for your needs? |
Just to remember, as I said at #223:
|
Ok, then the packages will contain the following: Voicing (this PR)
VoiceLeading (extra PR)
VoicingDictionary (extra PR)
Note (extra PR)
right? I could seperate the code sometime this weekend |
yeah i forgot that
those are possible future features, expressed as tests (the optional ones described in #223). That should not stay there..
ok |
Great, it looks like we have a plan. Nice addition the links to the voicing dictionaries 👏 I can prepare the |
Perfect! Those are the three tests that would need to pass for it to work: test('Note.enharmonic with second param', () => {
expect(Note.enharmonic('F2', 'E#')).toBe('E#2');
expect(Note.enharmonic('B2', 'Cb')).toBe('Cb3');
expect(Note.enharmonic('C2', 'B#')).toBe('B#1');
}); |
Just pushed an update. I have now
What's open
|
packages/tonal/index.ts
Outdated
import VoiceLeading from '@tonaljs/voice-leading'; | ||
import VoicingDictionary from '@tonaljs/voicing-dictionary'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm the pre commit hook messed something up here. I actually wanted to revert formatting everything with single quotes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tonal enforces prettier to be used, but it seems that is not working with you? 🤔 You can npm run format
to format the code (that's what the pre commit hook does). And it should result with double quotes. I don't know why is not the case...
EDIT: are you using a custom prettier config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume it uses my local prettier config because the project does not contain a prettier config
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
npm run format
also formats everything wrong (things that I did not even touch)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it might help adding a .prettierrc with your local setup
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right! I thought it was one... let me add it 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added a prettier configuration to package.json file: 638b5ef
Can you try to add the line "prettier": {},
to your package.json to see if it solves the problem?
Hi @felixroos,
🎉 Awesome...
Well, I'd really like it to be that way, because we could take care of little details of each. I'd start with dictionary. For example, I'm not convinced about But I understand it's a lot of work, so I had an idea:
How does it sound?
I've just merged a PR with the second
Yes, this is something I definitely want to fix before publishing (but we can merge and discuss the names in an issue).
It's ok. But it will be great to add the source links into a "Sources" / "Resources" section at dictionary's README.
Well, in summary:
What do you think?
Yes, this is a must before merge this PR
Weird, it works with for me... 🤔 You didn't change anything at chords dictionary, right? 😂 In any case, thank you very much! Let's fix those issues and merge. Good work!! 👏 👏 |
Hey, this is slowly getting somewhere!
That sounds like a plan.
Your change (adding prettier: {} to package.json) did the trick! I now ran formatting and it just modified the files I touched. Done!
This is the failed test:
It looks unrelated to any changes i've made (only added packages + changed tonal/index.ts + tonal/package.json). The test would pass if I adjusted the above lines.
done
So far there is one test for the only function. More to come
After integrating the upstream changes, the Note.enharmonic function is now available with two params! EDIT: It works! I just had to rebuild... Thank you
I understand that. I think it is kind of difficult to name voicings (also chords), as there is no "musicians committee for naming conventions" and there might be multiple ways of naming things. Being just a monophonic trumpet player myself, my knowledge about voicings mainly comes from 2 years of piano lessons in my jazz conservatory (where I just learned about lefthand voicings). Luckily, I have an old friend who is a professional jazz piano player who could maybe help me out with that. It might be debatable, but I think it is more important to "keep it real", using actual names that are known to musicians (as inconsistent as they might sometimes seem) than to use names that might be more logical, but not really used that way.
Alright Summary:
|
+ move VoiceLeading test
After thinking a little about possible future features, I had two ideas that could prevent possible breaking changes in the future: 1. VoicingDictionary should enable mapping multiple chord symbols to one set of intervalsBefore: export const lefthand: VoicingDictionary = {
m7: ["3m 5P 7m 9M", "7m 9M 10m 12P"],
/* more symbols */
} after: const lefthand = [
[['m7','m9'], ["3m 5P 7m 9M", "7m 9M 10m 12P"]],
/* more symbols */
]; This format allows mapping more than one symbol to a set of intervals. This resembles how many chord symbols are sometimes used synonymously. For example, in a jazz leadsheet, a "m7" is mostly played with a 9 (like above). If the sheet contains a "m9" instead, it is played exactly the same. Additionally, this makes it possible to define the same symbol multiple times, which could be useful for some scenarios. VoicingDictionary.lookup should therefore filter all dictionary items by the given symbol and concat all sets that match. 2. Voicing.get could be more generalTo allow adding other strategies to find voicings later (without needing to change Voicing.get / add a separate method). Before: function get(
chord: string,
range: string[] = defaultRange,
dictionary = defaultDictionary,
voiceLeading = defaultVoiceLeading,
lastVoicing?: string[]
) After: function get(
chord: string,
voicingGenerator: VoicingGenerator,
voiceLeading = defaultVoiceLeading,
lastVoicing?: string[]
) This method now has no hard wired connection to voicing dictionary. The voicingGenerator param expects a function that takes a chord and returns a set of intervals: type VoicingGenerator = (chord: string) => IntervalSet; As one way of generating voicings, we could create a generator with VoicingDictionary: VoicingDictionary.generator(range, dictionary) => VoicingGenerator; Example: const lookup = VoicingDictionary.generator(['E3','D5'], lefthand);
lookup('C^7')
/*
["E3", "G3", "B3", "D4"],
["E4", "G4", "B4", "D5"],
["B3", "D4", "E4", "G4"],
*/
// in practice, we might directly pass the generator to Voicing.get:
const { topNoteDiff } = VoiceLeading;
const lastVoicing = ["C4", "E4", "G4", "B4"];
Voicing.get('F^7', lookup, topNoteDiff, lastVoicing);
// ["C4", "E4", "F4", "A4"] Currently, there is only one way of generating voicings (dictionary), but this call signature would allow adding others later (like voicing permutation). Please tell me if this makes any sense? It is kind of abstract but I think it could be really powerful. |
I just made a little codesandbox to play around with (click "Open Sandbox" to edit) |
Wow! Nice! 😮
Very good point! 👍
Let's discuss in a separate issue ... So, I think we are ready to merge (and continue the discussion...). |
Yiha, thanks for the merge! I created three issues for the open points. See you there |
Even though it is merged, I cannot find any mention of this package in the Tonal README. Is the the Voicing package somehow available to be used? Any docs? |
Since the merge, it has never been release and it's still private. There are still some open issues:
These are now almost 2 years old and nothing has changed since then.. tbh I think I lost interest back then because the integration felt a little tedious. I ended up publishing my own package with the same functionality: https://github.com/felixroos/chord-voicings Still it would be nice to have this stuff integrated into tonal, so more people could use it. You can play around with the chord voicings package here: https://strudel.tidalcycles.org?wVExAEFBUPQB |
As already proposed in #223, this PR contains a first version of the Voicing package.
For now, this contains:
I also wrote basic test for all functions.
Open points:
yarn test:ci
generates a lot of changes that look like a different code formatting...I tried to adapt to the existing file structure / code style, but maybe there are things that could be optimized.
What do you think? I will now wait for your feedback, and maybe collect some voicings in the meantime 😊