-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Piano Roll Strum Tool #7725
base: master
Are you sure you want to change the base?
Piano Roll Strum Tool #7725
Conversation
Waow, Regulus, that looks very promising, in fact it can do much more than just strumming. At 1:25 you drag the bottom note of the chord to the left of the beat, and that my friend, is just what a real guitar player would do. He starts the strum before the beat, and the last note of the strum is exactly ON the beat of a bar, remember in a 4/4 measure there are 4 beats in a bar. Now, is there a way to use this feature in lets say an appimage of lmms? Thank you very much for your time. Jean |
Builds for this pull request are in "Actions" tab. For example here: |
Looks cool! Will be checking out! |
Seems like I accidentally took down the already present reviewers, my bad 😆 |
I am a total newbe when it comes to make/makeInstall. For some reason it keeps giving me errors by the dozen. So how can i download and use these builds from your link? |
@germona, please use https://lmms.io/download/pull-request/7725. You can do this for any active PR! 😄 |
Ok i have downloaded the appimage and the strumming works even better than i could have imagined....... |
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 tested this feature and found some issues:
In strum mode the user can click notes that aren't selected, this can result in unpredictable behaviour.
The notes can "slide under the piano keys" past the widget boundary on the left side. I believe this is unwanted.
int i = 0; | ||
for (Note* note: chord) | ||
{ | ||
float heightRatio = 1.f * i / (chord.size() - 1); |
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.
float heightRatio = 1.f * i / (chord.size() - 1); | |
float heightRatio = static_cast<float>(i) / static_cast<float>(chord.size() - 1); |
This doesn't look that simple, you could ignore this
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.
Does this improve performance or would the compiler automatically do this?
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'm not sure, I think it will result in the same code at the end of the day, but it is more explicit
If your chord starts at 'one', yes. Maybe have it restricted by default and then have an accelerator key to allow full motion to the left? I'm not sure what a negative note position in the pattern really means. I'll try and test this some more. |
Co-authored-by: szeli1 <[email protected]>
Co-authored-by: szeli1 <[email protected]>
I have added a |
Hm. Confusion ensues. Need to think about it... |
I can see some issue were found, please tag me when that is addressed and I'll take a look myself. |
Looks terrific! Taking a look now. |
It's outside the scope of this PR, but the ability to make selections while in the strum tool would be a great QOL feature. Additionally, using The undo works great. It would be very nice if the selection could remain when undoing the strum, as it is a different action to strumming, and thus shouldn't disappear when only strumming is undone. Consider the user messed up and wants to try the strum again. Currently, he has to:
And suppose he messes up again... 🤣 Alternatively (but not as good as keeping the selection), moving the keyboard shortcut somewhere closer to |
Awesome!! |
Thanks for testing!
I was originally intending to add this, but when I tried, it made everything waaaayy more complicated, and handling the logic with temporarily switching modes was not working very well, leading to a lot of edge case bugs.
That sounds like a great idea. Unfortunately, I do not fully understand how the undo system works, so implementing it would be difficult. Also fyi, you can exit from strum/knife mode by rightclicking. |
You can't implement this easily. I do not recommend requiring this feature (or implementing it in this pr). It would be nice, but it isn't worth it. The Journalling system wasn't made for this. |
@regulus79 I think the tool, how it is now is perfect. One can do the basic things a guitar player would do, and that is UpStrums and DownStrums. You can select one or more or all chords and ad a strum to them making sure that the last note of the strum is ON the beat of a bar. I don't know how it works with these push requests, but how big is the chance that this feature will be included in a new version of LMMS? Anyway thank you a lot for this wonderful feature. |
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.
Did you fix the issues about notes not moving I mentioned?
If yes, then I will approve this.
Could you describe what the expected behavior is supposed to be? (and maybe could you give a way to reproduce the issue?) zonkmachine gave a test project which exhibited a similar(?) effect when strumming, but I am fairly certain that in that case it was not a bug. Or well, I mean the strum tool in that case was not malfunctioning. I have it set so that chords which have different numbers of notes are strummed the same amount proportionally, with respect to each note's top/bottom note. So if one chord has five notes and one has four, and the user drags the bottom of one of the chords to the right, say, 20 ticks, then the notes in each of the chords will be spread out so that they span 20 ticks. The chord with 5 notes will have its notes spread 4 ticks apart, and the chord with 4 notes will have its note spread 5 ticks apart. This can sometimes look a bit strange, especially if the chords are right next to each other, but the notes are still spaced correctly, and it should still sound right. If you can come up with a better strumming algorithm, I would love to hear it. But so far this is the best idea I have. |
The chord with 5 notes will have its notes spread 4 ticks apart, and the chord with 4 notes will have its note spread 5 ticks apart. |
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 wasn't sure why the notes on the top of a chords didn't move when notes from other chords did move a the same height, but I see now that this is intended.
I tested and I approve this change.
Great PR! Just two requests:
|
Technically yes. But currently I keep the logic simple and only recalculate the chords when the strum tool is activated, whereas this would require calculating them every time the user clicks. One of the reasons I only calculate the chords at the very start is so that they still remain "separate" even when they are really distorted and overlapping. It might get complicated to have two different logics for whether notes are selected vs not.
This issue already exists in master with the knife tool. I can look into it, but I think it would require some effort to rework the way the gui handles the actions. Could we maybe deal with it in another PR? |
Would it be possible to get the "time" where the cursor is located and work on the notes in that section?
Maybe so, but it would be nice to uniform the behavior. You can move one note or a selection of notes. We're also adding cutting for selected notes as well as a single note. If a functionality logically can be used with and without the selection, I think we should provide it, for the sake of UX.
Even more reason to work on it! That would probably mean this is best suited for another PR, when this is merged.
Sure, if it is easier for you, but I'd think these are closely related to the core functionality. I could open an issue called "Improving the strum tool" where I list both of these issues and we can start work from there. If you're up, I can approve this an we can move it to the new issue! |
Done! Please note that using the strum tool without a selection may lead to odd behaviors if you strum a chord so that it overlaps with other notes, and then try to strum it back (since it will then calculate the selected chord as being all of those notes) Or if you strum a chord so long that it's notes no longer overlap each other. |
Alright, I've also added the ability to ctrl-select while in strum mode! |
Amazing! To not go out of scope, that works just for the strum tool? Or is it universal? |
Universal as in, for all tools? I only added it for the strum tool; I don't think it would really work for tools like the knife tool because ctrl does something (unquantization) in the knife tool. |
Totally understandable! I'll be testing this ASAP. Thank you! |
Due to the way I detect chords being prone to categorizing two chords as one if they overlap even slightly, I have reverted the ability to strum chords while not having any notes selected. @bratpeki found its behavior to be undesirable when strumming chords which are right next to each other, as they easily morph into one chord and become very odd to strum. |
This PR adds a complex strum tool to the PianoRoll, allowing the user to take a selection of chords, and drag around the notes to shape the strum exactly how they want it.
Additionally, holding
Shift
and moving the mouse up/down will make the notes in the strum follow a power curve, for greater flexibility.The current shortcut for the strum tool is
Shift+J
(Shift+S
was already taken) I'm not sure why I choseJ
, but if you have a better idea feel free to share it.Demo
strum_demo.mp4
How it works
I want you to think for a moment--how does a strum work? It's not a matter of shifting each note linearly based on their key, since after all, the notes may not be evenly spaced in the chord. You have to shift them based on the order you want them to be played in. So that's fine, just iterate up/down a chord, and shift the notes a bit based on their index, right? Well, ok, but how do you handle strumming multiple chords at once? That is the difficult part of the problem.
I couldn't solve it LOL. So instead I just did the easy thing and decided to group the selected notes into chords based on whether or not they were overlapping. So each chord is a little "island" of notes which are all connected if you squash the piano roll vertically. Then I perform the same strumming algorithm on each chord individually. I think it works pretty well, but there are some edge cases, like if two chords overlap, which may cause problems.
But there's another problem! What if two chords have different number of notes? Well, for simple strumming up/down, it's fine, just multiply the shift of each note by some proportionality constant and you're good to go. But what if you want to strum from a note in the middle of the chord? Well, I decided that it would make sense to strum all chords based on the ratio of where the strumming takes place in the chord. So if you start the strum in the middle of the chord, all other chords will be strummed from the middle. If you start it 3/4 of the way up, all the other chords will be strummed from 3/4 of the way up, relative to the number of notes they have (not the key positions!)
In the code, it looks like this:
Note::setOldPos
.Shift
is held down.Changes
The base code was copied from the
Knife
action, so there are many similarities in how it is handled.Strum
as anAction
andEditMode
setStrumAction()
andcancelStrumAction()
methods, modeled after theKnife
tool's methods.NoteVector
s,m_selectedChords
was added to store the list of notes for each chord to be strummed.setupSelectedChords()
was added to initialize the vector of chords.updateStrumPos()
was added to update the note positions as the mouse moves during the strum.