Skip to content
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

Keyboard shortcuts to preview/add sounds from sidebar #5427

Merged
merged 18 commits into from
Oct 3, 2020

Conversation

Spekular
Copy link
Member

@Spekular Spekular commented Mar 23, 2020

Now ready for testing and review

The file browser now behaves as follows:

  • Pressing arrow keys, space, or enter/return will cancel any running previews
  • Pressing up/down moves to the previous/next item
    • If the new item is a sample, it will automatically preview
    • If the key is held down and auto-repeats, previews are suppressed
  • Holding space previews the current item. The preview ends when space is released.
  • Enter/return sends the current item to the song editor as an instrument
    • Samples can be sent to a new sample track instead by holding shift
    • Holding control sends to the BB editor instead
    • Samples can't be sent as sample tracks to the BB editor (wontfix), so ctrl+shift does nothing
  • RMB context menu gets fake headers, however legibility isn't ideal

Preset Menu
Sample Menu

Todo:

  • Sustained presets shouldn't play indefinitely. Only play presets while left arrow held? Done
  • Shift + right arrow to add a sample to a new (empty) sample track in song editor Done
  • Ctrl + shift + right arrow to add a sample to a new (empty) sample track in BB editor Not feasible, nor particularly useful.

Code quality is iffy at best right now, among other things I did some questionable refactoring in the context menu code. The commit "DRY up code and ..." vastly improves this

@LmmsBot
Copy link

LmmsBot commented Mar 23, 2020

🤖 Hey, I'm @LmmsBot from github.com/lmms/bot and I made downloads for this pull request, click me to make them magically appear! 🎩

Linux

Windows

macOS

🤖
{"platform_name_to_artifacts": {"Linux": [{"artifact": {"title": {"title": "(AppImage)", "platform_name": "Linux"}, "link": {"link": "https://9239-15778896-gh.circle-artifacts.com/0/lmms-1.2.3-736%2Bgebe30f8-linux-x86_64.AppImage"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/9239?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}], "Windows": [{"artifact": {"title": {"title": "32-bit", "platform_name": "Windows"}, "link": {"link": "https://9240-15778896-gh.circle-artifacts.com/0/lmms-1.2.3-736%2Bgebe30f88f-mingw-win32.exe"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/9240?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}, {"artifact": {"title": {"title": "64-bit", "platform_name": "Windows"}, "link": {"link": "https://9242-15778896-gh.circle-artifacts.com/0/lmms-1.2.3-736%2Bgebe30f88f-mingw-win64.exe"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/9242?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}, {"artifact": {"title": {"title": "32-bit", "platform_name": "Windows"}, "link": {"link": "https://ci.appveyor.com/api/buildjobs/rm3ukilko9fvn74l/artifacts/build/lmms-1.2.2-msvc2017-win32.exe"}}, "build_link": "https://ci.appveyor.com/project/Lukas-W/lmms/builds/35551388"}, {"artifact": {"title": {"title": "64-bit", "platform_name": "Windows"}, "link": {"link": "https://ci.appveyor.com/api/buildjobs/f5fudlp3mrbvncep/artifacts/build/lmms-1.2.2-msvc2017-win64.exe"}}, "build_link": "https://ci.appveyor.com/project/Lukas-W/lmms/builds/35551388"}], "macOS": [{"artifact": {"title": {"title": "", "platform_name": "macOS"}, "link": {"link": "https://9243-15778896-gh.circle-artifacts.com/0/lmms-1.2.3-736%2Bgebe30f88f-mac10.13.dmg"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/9243?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}]}, "commit_sha": "9d60c0ea58f99493b255d9a5e3232281b755a581"}

src/gui/FileBrowser.cpp Outdated Show resolved Hide resolved
src/gui/FileBrowser.cpp Outdated Show resolved Hide resolved
src/gui/FileBrowser.cpp Outdated Show resolved Hide resolved
@Spekular Spekular added needs code review A functional code review is currently required for this PR needs testing This pull request needs more testing and removed in progress labels Sep 23, 2020
@Spekular Spekular marked this pull request as ready for review September 23, 2020 20:22
@Spekular
Copy link
Member Author

IMHO this should close #5671. The proposal there isn't an improvement as far as I'm concerned, and with this merged it makes even less sense.

Copy link
Contributor

@Veratil Veratil left a comment

Choose a reason for hiding this comment

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

The nullptr comment scopes across the whole review.

src/gui/FileBrowser.cpp Outdated Show resolved Hide resolved
src/gui/FileBrowser.cpp Outdated Show resolved Hide resolved
@Spekular
Copy link
Member Author

FYI, CircleCI mac failure looks unrelated (it fails to fetch homebrew).

@Spekular
Copy link
Member Author

Spekular commented Sep 29, 2020

The latest commit is a bit of a shot in the dark, the overhead from locking/unlocking more often and changing m_previewFileItem might cancel out the benefit of not hogging the lock as long (not to mention the fact that potentially neither of those are the issue). That being said, as far as I can tell it shouldn't introduce threading issues.

  • Previously: The code that I extracted into previewFileItem locked the preview mutex immediately, and only unlocked before returning. The code that I extracted into stopPreview was also completely wrapped in lock/unlock. Thus, whatever function entered the lock most recently would be the one that took effect.
  • Now: previewFileItem and stopPreview immediately lock and then set m_previewFileItem before unlocking. Whatever function entered the lock most recently decides the state of m_previewFileItem, which in turn decides what action will take effect.

If this commit works, I'll add comments clarifying that access to m_previewFileItem and m_previewPlayHandle should be protected by m_pphMutex (which should maybe be renamed to m_previewMutex?). If it fails or someone has objections, I'll revert the changes affecting when locks are aquired/released, but leave the use of QMutexLocker.

@Spekular
Copy link
Member Author

Testing doesn't reveal any apparent difference, which isn't surprising. In hindsight it's pretty obvious that making the preview lock in FileBrowser available slightly faster wouldn't help, but it was an easy thing to check.

@Spekular Spekular changed the title Preview/add samples/presets with arrow keys Keyboard shortcuts to preview/add sounds from sidebar Sep 29, 2020
@Spekular Spekular requested a review from Veratil September 30, 2020 14:38
Copy link
Member

@DomClark DomClark left a comment

Choose a reason for hiding this comment

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

Regarding m_pphMutex, couldn't it be removed altogether? From what I can tell, it's only ever locked from the UI thread, so there's nothing for it to protect against.

src/gui/FileBrowser.cpp Outdated Show resolved Hide resolved
include/FileBrowser.h Outdated Show resolved Hide resolved
src/gui/FileBrowser.cpp Outdated Show resolved Hide resolved
src/gui/FileBrowser.cpp Outdated Show resolved Hide resolved
@Spekular
Copy link
Member Author

Regarding m_pphMutex, couldn't it be removed altogether? From what I can tell, it's only ever locked from the UI thread, so there's nothing for it to protect against.

My understanding is that it prevents several calls created via UI input from interfering with each other. Is this not necessary?

For example, if you very quickly tap the spacebar, couldn't this happen without locks?

  • previewFileItem gets as far as checking m_previewPlayHandle != nullptr
  • stopPreview sets the play handle to nullptr
  • We end up calling call Engine::getMixer()->addPlayHandle() with a nullptr argument

Also, as far as I can tell C++ makes no guarantees that a variable is in a valid state when read in unsynchronized code. Isn't this alone a good reason to avoid concurrent access?

@Spekular
Copy link
Member Author

Ah wait, you mean that all the modifications to the play handle originate from UI events and thus run on the UI thread, so there's no concurrency happening. That makes sense, but to me it raises the issue that perhaps some of this work should actually happen outside the UI thread.

@DomClark
Copy link
Member

... it raises the issue that perhaps some of this work should actually happen outside the UI thread.

True - it would definitely be nice to load samples (and presets too, I guess) asynchronously. Let's leave it in for now.

@Spekular
Copy link
Member Author

Spekular commented Oct 1, 2020

Thanks for the review, @DomClark! Recent commits should address the issues you brought up.

I also tried replacing the preview mutex with a QThreadPool, but QRunnable::create(... lambda expression...) is only in Qt 5.15 and later and we're quite a bit behind. Anyway, the idea was as follows:

  • Create a thread pool with a maximum of one thread. As long as all access to m_previewPlayHandle happens by starting QRunnables on the thread pool, we achieve thread confinement for the play handle and also get out of the event thread's way.
  • previewFileItem and stopPreview would initially call clear() on the thread pool, clearing any queued-but-not-started tasks (since they're outdated). Then they would call start(QRunnable::create(... do all the work in a lambda...)). This should let the thread pool take care of their work ASAP unless another, newer, event comes along first.
  • mouseReleaseEvent would just queue itself. It wouldn't call clear(), since it may or may not need to stop the preview.

Copy link
Contributor

@Veratil Veratil left a comment

Choose a reason for hiding this comment

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

The only other thing I see is no whitespace between parenthesis and curly brace in if (){ .. }.

include/FileBrowser.h Outdated Show resolved Hide resolved
Comment on lines +340 to +342



Copy link
Contributor

Choose a reason for hiding this comment

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

I recall somewhere about having 4 newlines between functions, but I don't know if we care to keep doing that? I say because this hunk is unrelated to PR, and more a formatting update.

Copy link
Member Author

Choose a reason for hiding this comment

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

I wanted to keep FileBrowserTreeWidget's spacing a bit more consistent since it varied before, but I can undo this if you'd like.

Copy link
Member

Choose a reason for hiding this comment

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

FWIW, I don't like the four newlines. (I'm generally in favour of anything that uses less vertical space.)

Copy link
Member Author

@Spekular Spekular Oct 2, 2020

Choose a reason for hiding this comment

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

I would also prefer a single newline between functions of the same class, but I've generally stuck with four in order to have some semblance of consistency.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah - I don't think it should be changed here, but it might be a candidate for the reformatting if others agree.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be a thing for the clang-tidy/format PR.

src/gui/FileBrowser.cpp Show resolved Hide resolved
src/gui/FileBrowser.cpp Show resolved Hide resolved
@Spekular
Copy link
Member Author

Spekular commented Oct 2, 2020

Thanks for the review @Veratil! I've fixed the event handler visibility and spacing in if statements, and also fixed some inconsistent spacing between FileBrowserTreeWidget's methods. I can revert the spacing changes if you'd like, but figured if they're going to be there they should be consistent.

@Spekular
Copy link
Member Author

Spekular commented Oct 3, 2020

Any objections to me merging this? There are technically no approving reviews, I suppose, but I've fixed the issues brought up in review and no one has mentioned new ones so far.

src/gui/FileBrowser.cpp Outdated Show resolved Hide resolved
src/gui/FileBrowser.cpp Outdated Show resolved Hide resolved
@Spekular Spekular merged commit 109a7c4 into LMMS:master Oct 3, 2020
@Spekular Spekular deleted the browserShortcuts branch October 3, 2020 19:31
{
s->setDoneMayReturnTrue( true );
m_previewPlayHandle = NULL;
Copy link
Member

@PhysSong PhysSong Oct 31, 2020

Choose a reason for hiding this comment

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

I think this removed line(m_previewPlayHandle = NULL;) is the key of #5736. Mixer will cleanup the play handle later, and we won't stop previewing in this case.

sdasda7777 pushed a commit to sdasda7777/lmms that referenced this pull request Jun 28, 2022
- Extract file item preview start and end into new methods `previewFileItem` and `stopPreview`.
- Add event handlers:
  - `keyPressEvent` to allow auto preview (on up/down arrow navigation), manual preview (space), and send to editors (enter)
  - `keyReleaseEvent` to end previews when preview key is released
  - `hideEvent` to end previews when switching sidebar tab or hiding sidebar
- Functions that operate on a `FileItem` now take it as an argument instead of using a member variable
- `getContextActions` provides menu items for sending clips to the song editor and BB editor with minimal duplicate code
- Some formatting changes in affected code
- Replace many instances of `NULL` with `nullptr`
@Spekular Spekular mentioned this pull request Jun 7, 2024
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs code review A functional code review is currently required for this PR needs testing This pull request needs more testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants