-
Notifications
You must be signed in to change notification settings - Fork 239
Add MIDI GUI tab and learn function #3502
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
base: main
Are you sure you want to change the base?
Conversation
|
Thanks for this contribution. It looks like a useful feature. I will be happy to test it in due course, on Linux, Windows and Mac, but at the moment most of my kit is packed away for a pending house move. |
|
@softins thanks - no worries, I guess there will be plenty of time for testing before this ever makes it in (if it does). Hope the house move goes smoothly. |
|
Nice! I'd like to open a discussion:
|
In any event, this is still under development as I'm finding that some of my implementations are far from perfect. E.g. the way the MIDI in port is currently kept open I think has been done wrong, so I'm working on that. I'm testing a version where the MIDI port can be enabled/disabled at runtime, as among other things it affects whether numbers are prepended to user names in the mixer board - if you're not using MIDI you won't want that. The main purpose for opening this PR was to generate builds for other platforms for testing, but for now it's just a PoC that's far from finished, so any suggestions are welcome. |
|
Tested on Linux, Windows (no JACK) and macOS (legacy and non-legacy), and it seems to be working on these three platforms at least. |
|
OK just stumbled onto this. As this is a new feature, the following need to be adhered to:
(The "learn" feature for JSONRPC would just be the eventual "set X to Y" update, the visual behaviour would be for the JSONRPC user to supply - it just needs to be able to send the same update to the core code as the Client UI.) |
pljones
left a comment
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.
Get rid of all the unnecessary changes in spacing and resubmit the PR. As it stands, I can't review it.
Done. Those keep getting added in by clang.
It's been almost a year since I did this, but as far as I recall it updates the main application state via pSettings and pClient. |
|
I believe this should be rebased and squashed into one commit. |
It looks pretty good -- as @ann0see says, please rebase and squash. Then check the resultant diff for anything obvious 😄 - it looks mostly okay to me but there's a few places I'm not sure what was being intended, so I might have some more questions. One thing I might ask is for the command line parsing code to be moved into |
fe82247 to
7097b29
Compare
Done.
Done. I don't know what clang is whining about - I can't use it because it reformats a ton of stuff that shouldn't be. |
Known issue. We should really bump the clang format version. Otherwise be sure to use the same clang format version as used in the CI |
I've been working on this - should the UI immediately reflect changes from JSONRPC commands sent? It doesn't seem to do this for the existing commands but just to confirm. |
The problem is that in the TODO blocks, the TODO lines don't have a space after |
26f4096 to
1f2f394
Compare
1f2f394 to
f8a5b2d
Compare
|
|
||
| virtual float GetInOutLatencyMs() { return fInOutLatencyMs; } | ||
|
|
||
| // MIDI port toggle |
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.
As these are in CSoundBase, do they need to be in each inheriting class?
src/sound/soundbase.cpp
Outdated
| const CMidiCtlEntry& cCtrl = aMidiCtls[vMIDIPaketBytes[1]]; | ||
| const int iValue = vMIDIPaketBytes[2]; | ||
| emit MidiCCReceived ( vMIDIPaketBytes[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.
And this shouldn't be here -- clang should have caught it.
b8861be to
099455b
Compare
|
Removing the declarations from the Asio, JACK and macOS headers prevents them from compiling. I added them back in as I don't really know what else to do. |
099455b to
45b8b58
Compare
src/settings.cpp
Outdated
| pClient->SetAudioQuality ( static_cast<EAudioQuality> ( iValue ) ); | ||
| } | ||
|
|
||
| // MIDI settings |
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.
@pljones would you prefer a loop here too?
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.
Map from "whatever" to [this]() { GetNumericIniSet ( IniXMLDocument, "client", "whatever", minWhatever, maxWhatever, iValue ); this->whatever = iValue; }; and then loop over an array of them?
Or do "midichannel" and "usemidicontroller" separately, with everything in the loop with the 0, 127 hardcoded... I'd go with that, I think.
| bMuteMeInPersonalMix ); | ||
|
|
||
| // load settings from init-file (command line options override) | ||
| // Create Settings with the client pointer |
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.
The deleted line is correct -- but for the Settings.Load line.
src/main.cpp
Outdated
| CSoundBase::ParseMIDICommandLineParams ( strMIDISetup, Settings ); | ||
| if ( Settings.bUseMIDIController ) | ||
| { | ||
| Client.ApplyMIDIMapping ( Settings.GetMIDIMapString() ); |
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.
This now seems counter-intuitive.
Maybe CSoundBase::ParseMIDICommandLineParams ( strMIDISetup, Settings ); should be in settings (it wouldn't need to keep calling into Settings, then).
Given the command line arg has been parsed out into separate values in Settings, turning it back into a string so that it can be parsed out into separate settings again... Client already has a Settings reference, so it can go read the values.
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.
See other comment about this.
| bWindowWasShownSettings ( false ), | ||
| bWindowWasShownChat ( false ), | ||
| bWindowWasShownConnect ( false ), | ||
| bOwnFaderFirst ( false ), |
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 need to follow this style for all the new entries.
src/settings.h
Outdated
| bool bOwnFaderFirst; | ||
|
|
||
| // MIDI settings | ||
| int midiChannel = 0; // Default MIDI channel 0 |
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.
These really should all be iMidi... by convention.
| int midiMuteOffset = 0; | ||
| int midiMuteCount = 0; | ||
| bool bUseMIDIController = false; | ||
| QString GetMIDIMapString() const; |
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.
As other note, I'd like this to go away.
| /// @param {object} params - Any subset of MIDI settings fields to set. | ||
| /// @result {string} result - Always "ok". | ||
| pRpcServer->HandleMethod ( "jamulusclient/setMidiSettings", [=] ( const QJsonObject& params, QJsonObject& response ) { | ||
| if ( params.contains ( "bUseMIDIController" ) ) |
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.
Do I trust Gemini to write C++?
std::unordered_map<String, std::function<void(String)>> setters = {
{ "bUseMIDIController", [this](String name) { m_pSettings->bUseMIDIController = params[name].toBool(); },
{ "midiChannel", [this](String name) { m_pSettings->midiChannel = params[name].toInt(); },
...
};
// Iterate through every defined setter in your map
for (const auto& [name, setter] : setters)
{
// Check if the incoming params collection actually has this key
if (params.contains(name))
{
// Execute the lambda: [this](String n) { ... }
setter(name);
}
}
(And it followed Jamulus coding style better than I did...)
src/sound/soundbase.cpp
Outdated
| * MIDI handling * | ||
| \******************************************************************************/ | ||
|
|
||
| void CSoundBase::ParseMIDICommandLineParams ( const QString& strMIDISetup, CClientSettings& Settings ) |
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.
Yeah, sorry -- move to CSettings.
src/sound/soundbase.cpp
Outdated
| Settings.bUseMIDIController = true; | ||
| } | ||
| } | ||
| void CSoundBase::ParseCommandLineArgument ( const QString& strMIDISetup ) |
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 think you need to make sure there's only one way of doing this. This existing method is "the one true agreed way" to parse the command line.
Ideally it needs to move to CSettings and only update the values you're now storing.
Then CClient should tell CSound what to do when it initialises:
- set up the initial MIDI mapping
- check whether MIDI needs to be enabled and, if so, turn it on
The UI and RPC should tell CClient what's going on and it should update CSettings - the UI and RPC shouldn't directly update Settings -- CSettings is meant to be fairly dumb with any logic in CClient or CServer. Currently, that's not generally how things are done though.
src/sound/soundbase.cpp
Outdated
| void CSoundBase::SetMIDIMapping ( const QString& strMIDISetup ) | ||
| { | ||
| // Parse the MIDI mapping | ||
| ParseCommandLineArgument ( strMIDISetup ); |
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 don't like passing this around as a string.
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.
Actually, with the proposed change above, the whole thing can go.
src/main.cpp
Outdated
| iQosNumber, | ||
| strConnOnStartupAddress, | ||
| strMIDISetup, | ||
| "", // Always start with empty MIDI |
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.
So change the method signature.
|
@pljones I had a go at addressing most of your comments - the biggest change being moving the MIDI command line parsing to |
Adds a MIDI tab to the Settings menu and exposes the MIDI parameters so they can be changed via the GUI. MIDI CC numbers can be automatically set using "learn" buttons that when pressed, listen for an incoming MIDI message and store it. Starting Jamulus with
--ctrlmidichcommand line arguments overrides and replaces those set via the GUI.The MIDI-in port can be enabled/disabled at runtime instead of it being determined at launch by the
--ctrlmidichparameter or by making it permanently open. This means that user names are prepended by a number depending on whether the MIDI in port has been enabled or not (as is the case now).I've also ditched the "Offset" term, at least for the GUI. It's a hangover from the days when that's what it was, a value hard-coded for a specific Behringer device, but in the current context it no longer makes sense.
EDIT: Added JSONRPC support.
CHANGELOG: Client: Added MIDI tab to Settings GUI exposing MIDI parameters. MIDI Learn feature also added.
Context: Fixes an issue?
Does this change need documentation? What needs to be documented and how?
Needs to be documented.
Status of this Pull Request
Working on Linux, Windows and macOS but should be tested more thoroughly.
What is missing until this pull request can be merged?
Further testing and code review.
Checklist