SanderVocke / winmm_midi_rename

WinMM wrapper which enables rule-based modification of MIDI device properties.
GNU General Public License v3.0
7 stars 1 forks source link

Pioneer DJ controllers and Rekordbox #4

Open SanderVocke opened 4 months ago

SanderVocke commented 4 months ago

Creating this issue because I have had two people come forward with unsuccessful attempts to connect DJ controllers to Rekordbox on Wine in Linux using this wrapper. Let's discuss here.

TL;DR of the progress so far:

@elvetemedve gave repeated feedback to improve the wrapper and add more spoofing features. Currently stuck because Rekordbox starts querying directly to the USB device layer, going further than just midi. It seems that this is not a pure MIDI device.

That being said, if you own another device compatibly with Rekordbox, it is still worth a shot to try it with the latest release of this repo. We don't know if Rekordbox behaves the same for every single controller.

SanderVocke commented 4 months ago

@elvetemedve reported using the following config for a DDJ-FLX10 after using the wrapper to determine the correct values on Windows:

{
    "log": "midi_rename.log",
    "popup": true,
    "rules": [
        {
          "match_name": "DDJ-FLX10 - DDJ-FLX10 MIDI.+",
          "match_direction": "out",
          "replace_name": "DDJ-FLX10",
          "replace_man_id": 65535,
          "replace_prod_id": 65535,
          "replace_channel_mask": 65535,
          "replace_driver_version": 274,
          "replace_technology": 1
        },
        {
          "match_name": "DDJ-FLX10 - DDJ-FLX10 MIDI.+",
          "match_direction": "in",
          "replace_name": "DDJ-FLX10",
          "replace_man_id": 65535,
          "replace_prod_id": 65535,
          "replace_driver_version": 274
        }
    ]
}

With the following result:

Request for output device capabilities:   name: DDJ-FLX10 - DDJ-FLX10 MIDI 1
  man id: 255
  prod id: 1
  driver version: 1
  technology: 1
  voices: 0
  notes: 0
  channel mask: 65535
  support: 0

--> Matched a replace rule. Returning:   name: DDJ-FLX10
  man id: 65535
  prod id: 65535
  driver version: 274
  technology: 1
  voices: 0
  notes: 0
  channel mask: 65535
  support: 0

Request for input device capabilities:   name: DDJ-FLX10 - DDJ-FLX10 MIDI 1
  man id: 255
  prod id: 1
  driver version: 1

--> Matched a replace rule. Returning:   name: DDJ-FLX10
  man id: 65535
  prod id: 65535
  driver version: 274

... But not recognized in Rekordbox.

I got a very similar experience in a private message, in that case it was a DDJ-RB.

SanderVocke commented 4 months ago

To me, there are a couple of options of what could be going wrong:

  1. Maybe there is still something wrong in the values configured in the configuration. It seems suspicious that on Windows, we always get man id and prod id of 65535 - it could be a bug. A next step could be to go on Windows and find a tool which can also inspect these properties independently. If such a tool also would report 65535 on Windows, we know we are doing the correct thing here and we can rule out this potential issue.
  2. Maybe there is still some other property missing in the wrapper. It seems unlikely to me - the properties supported, as far as I know, completely cover all device properties that the WinMM midi API has. You could verify this independently: https://learn.microsoft.com/en-us/windows/win32/api/mmeapi/
  3. Maybe the Rekordbox software is talking to the controller using more than just MIDI. After all, it is a USB device. If it turns out that Rekordbox verifies the device with some non-MIDI communication, this wrapper tool is not going to help. It will be difficult to get around in that case, because AFAIK, WINE does not support USB drivers in the Windows side.

One thing I would suggest is to install MidiView (https://hautetechnique.com/midi/midiview/) both in Windows, and in WINE on Linux. Use it to monitor the MIDI communication when the device is connected. Check if the kinds of messages being sent and received are the same in both environments.

In my own use-case (a Joue Play MIDI controller and app), the wrapper worked fine, but of course the application could be doing less checks.

I myself am happy to support by e.g. fixing bugs if it turns out that, for example, the man id / prod id thing is somehow broken. But I am not willing to actively help analyze communications or something of that nature - I would rely on input from you.

Good luck, I hope it ends up working!

SanderVocke commented 4 months ago

There is one level deeper you could go in analyzing the differences in Windows and WINE: use something like API monitor (http://www.rohitab.com/apimonitor). You could track exactly what Windows Multimedia API calls the Rekordbox application is making, including the exact values returned by Windows or WINE to the application.

Maybe this would reveal some difference in behavior between WINE and Windows that this wrapper could solve.

SanderVocke commented 4 months ago

One last suggestion: I read that the DDJ-FLX10 also supports Serato DJ Pro. Maybe install a free trial of that in WINE and see if it picks up the device? Just as a sanity-check, you never know.

SanderVocke commented 4 months ago

... And another addition. I found a blog post of someone in 2019 achieving the connection with DDJ-SX2. I don't know which WINE version and which Rekordbox version was used. https://www.erhan.es/blog/using-pioneer-controller-with-rekordbox-in-linux/

He essentially does the same thing as this wrapper library does, but instead of using a wrapper DLL he modified WINE itself to do the same name re-mapping. He was able to get it working by only remapping the name, not the IDs.

Please have a detailed look at what he did, and maybe you can replicate. Who knows, maybe you should only remap the name and not the IDs?

SanderVocke commented 4 months ago

In any case, I would appreciate if you let me know here if/when your attempts are successful. Maybe someone else will benefit.

elvetemedve commented 4 months ago

@SanderVocke Thank you for sharing your view and the suggestions.

I explored some of these options. The API Monitor was the one that provided the most details:

The DJ controller is the device ID 3 and the name is "DDJ-FLX10". All midiInMessage() call failed. Screenshot from 2024-07-22 00-00-39

This shows that both midiInMessage() and midiOutMessage() failed, but with different return value. Screenshot from 2024-07-22 00-05-02

Device ID 1 is the virtual device "PipeWire-RT-Event input". Screenshot from 2024-07-22 00-05-57

SanderVocke commented 4 months ago

That's interesting info, and also taught me something I didn't know yet about the MIDI API on Windows.

Looking in the docs of midi*Message() (see e.g. https://learn.microsoft.com/en-us/windows/win32/api/mmeapi/nf-mmeapi-midiinmessage), apparently these functions are used not to send MIDI messages, but to send messages (queries) to the driver.

the message is the second argument (2061 in your screenshots). Digging a bit further, the following is the list of queries mentioned in the MSDN docs above:

#define DRV_QUERYDEVNODE (DRV_RESERVED + 2)
#define DRV_QUERYMAPPABLE (DRV_RESERVED + 5)
#define DRV_QUERYMODULE (DRV_RESERVED + 9)
#define DRV_PNPINSTALL (DRV_RESERVED + 11)
#define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12)
#define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13)
#define DRV_QUERYSTRINGID (DRV_RESERVED + 14)
#define DRV_QUERYSTRINGIDSIZE (DRV_RESERVED + 15)
#define DRV_QUERYIDFROMSTRINGID (DRV_RESERVED + 16)
#define DRV_QUERYFUNCTIONINSTANCEID (DRV_RESERVED + 17)
#define DRV_QUERYFUNCTIONINSTANCEIDSIZE (DRV_RESERVED + 18)

where DRV_RESERVED is 0x800 (so 2048).

That would suggest that Rekordbox is querying for DRV_QUERYDEVICEINTERFACESIZE, which is usually the first step before querying DRV_QUERYDEVICEINTERFACE to get a driver-level device name.

In other words, looks like Rekordbox is using this advanced method to query the device name, instead of just relying on the device properties we have spoofed. If we are lucky, this is just a final check before really starting to talk to the device. And these calls could be spoofed by this wrapper just like we are spoofing the other calls.

I would suggest:

No guarantees that this will work, but at least it is not a dead end.

SanderVocke commented 4 months ago

One more thing, does the API monitor tool support exporting/importing a logged session? If so, could you record the behavior on Windows and share it?

elvetemedve commented 4 months ago

Looking in the docs of midi*Message() (see e.g. https://learn.microsoft.com/en-us/windows/win32/api/mmeapi/nf-mmeapi-midiinmessage), apparently these functions are used not to send MIDI messages, but to send messages (queries) to the driver.

You are right. I didn't pay attention to this detail. Thanks for noticing. It looks like before talking to the device it has to call midi*Open() first.


Can you have a close look on Windows with the API monitor, and see what calls to midi*Message are made exactly?

As far as I see midi*Message() functions are called in pairs, first with 2061 as message, secondly 2060. Based on your observation, these must be the DRV_QUERYDEVICEINTERFACESIZE and DRV_QUERYDEVICEINTERFACE messages. That must be the way Rekordbox obtains the device name.


No guarantees that this will work, but at least it is not a dead end.

Yeah, there is hope fortunately. Though I noticed that these function pairs are called multiple times until the midi*Open() call takes place. So there could be a loop, or callback that is waiting until a condition is met (the open question is what are these conditions and will these be fulfilled under Wine).


Combining these two steps, I could then add extra features to be able to spoof these queries.

If you can put the effort into that, it would be very nice.


One more thing, does the API monitor tool support exporting/importing a logged session? If so, could you record the behavior on Windows and share it?

Sure, I've saved the capture of function calls. You should be able to open and inspect it after extracting the zip file: midi-api-capture.zip

SanderVocke commented 4 months ago

Nice. I will get back to you some time later this week with an update to log these calls.

SanderVocke commented 4 months ago

In the meantime, you can already use this tool I found (midienum.exe) to check and compare the device interface name on WINE vs. Windows:

https://matthewvaneerde.wordpress.com/2012/09/21/enumerating-midi-devices/

SanderVocke commented 4 months ago

You can have a try with this modified wrapper:

release-dll.zip

It should now also log the queries to DRV_QUERYDEVICEINTERFACE(...) in the log file.

You can add an entry to your replace rules: "replace_interface_name", to match the Windows name in WINE.

I didn't test this myself, sorry, so it may not work correctly. Otherwise, it would be good to also have a look with the midi enum tool above.

elvetemedve commented 3 months ago

Thank you for the updated version.

I've checked out the interface name by both methods on Windows 10 and got the same text:

\\?\usb#vid_2b73&pid_0041&mi_03#9&2f46a9a1&0&0003#{6994ad04-93ef-11d0-a3cc-00a0c9223196}\global

Based on that I've updated the config file: midi_rename_config.json

Unfortunately it does not load the rules properly ("# of rules loaded 0"). image

Could you have a look what might be wrong there, please?

SanderVocke commented 3 months ago

Sure, I'll have a look. I really should have tested it myself first. I can't get around to it until Monday though.

I am curious, what is the interface name when running with wine?

elvetemedve commented 3 months ago

Possibly I made a mistake somewhere, because now I got different info in the popup for the same config JSON: Screenshot from 2024-07-29 00-44-11


Sure, I'll have a look. I really should have tested it myself first. I can't get around to it until Monday though.

I am curious, what is the interface name when running with wine?

The interface name is just a number under Wine. For example --> Transparently queried the device interface with result: Queried device interface size for input. Native result: 1448556300 midi_rename.log

SanderVocke commented 3 months ago

It could be that the interface isn't always exactly the same. But it wouldn't be hard to imagine that Rekordbox does some basic check on it so that it looks "Windows-like" and not just a number like WINE.

Hang in there - I don't have a lot of time this week but I will get around to fixing the config bug at some point.

elvetemedve commented 3 months ago

It could be that the interface isn't always exactly the same. But it wouldn't be hard to imagine that Rekordbox does some basic check on it so that it looks "Windows-like" and not just a number like WINE.

Actually Rekordbox needs to recognize the controller for two purposes:

  1. To load the device specific midi mapping. Maybe the device name as text is good enough for this.
  2. Certain paid features are unlocked when a Pioneer controller is connected. I can imagine they do some trickery because of that to prevent getting those features for free by simply faking the name.

Hang in there - I don't have a lot of time this week but I will get around to fixing the config bug at some point.

Sure, thanks for the update.

SanderVocke commented 3 months ago

Actually Rekordbox needs to recognize the controller for two purposes:

I agree, I just meant that maybe it doesn't use only this interface name for device recognition. It could be doing some checks on the interface name and then combining that with the Midi device name.

It is a bit unclear to me, but I think that the interface name contains information both about the device and about the Midi hardware and/or driver used to connect to it.

SanderVocke commented 3 months ago

release-dll(2).zip Thanks for waiting, I got around to it. Bug with loading rules should be fixed (along with strange characters that were printed in the message box), although I am still not able right now to test this with a real MIDI device.

Can you try again with this DLL and the same config file?

Also one remark about --> Transparently queried the device interface with result: Queried device interface size for input. Native result: 1448556300: notice that it says "interface size", not "interface name". It first asked how long the name is. So it is supposed to be a number - although 1448556300 is a strange answer.

Anyway, please have a try and next time if something is wrong I will be able to respond faster.

elvetemedve commented 3 months ago

No worries. Thanks for your effort to keep investigating this.

Can you try again with this DLL and the same config file?

I tested it and the rules are loaded successfully this time. However faking the Windows API call still does not look right to me. In the log I see empty string as device name (--> Transparently queried the device interface with result:), while API Monitor still captured midiInMessage(*, 2061, *) calls returning MMYSYERR_INVALIDHANDLE, and of course Rekordbox does not recognize the MIDI controller.

notice that it says "interface size", not "interface name".

My bad, sorry about that. I add the full log here.

midi_rename.log

Do you have any other idea what went wrong?

SanderVocke commented 3 months ago

Sorry for my delayed response. I guess responding quickly didn't really happen.

Do you also have logs from the API monitor (both on Windows and on WINE)?

elvetemedve commented 3 months ago

No worries. 🙂

Sure, I will do, but can't until the middle of next week.

elvetemedve commented 2 months ago

Here are the logs captured under both Windows and Linux: logs.zip

SanderVocke commented 2 months ago

Thanks! This is very informative. The API monitor gives a lot of info, although not all - unfortunately, arguments passed as pointers to the system layer have invisible values to the API monitor.

But it seems you are right about the MMYSYERR_INVALIDHANDLE. For some reason, making these driver-level calls to the Wine implementation returns errors and empty device names. I am not sure if that is some kind of bug - it could simply be that these features are not supported in Wine. I had a quick look at the Wine source code but couldn't track it down.

We don't necessarily need to know the exact problem though. We are trying to spoof the device name anyway. I think we can just return a success code to Rekordbox and the spoofed name, even if the actual system gives error codes. To Rekordbox it would look like a successful call.

I'll go ahead and implement that and you can try it out.

SanderVocke commented 2 months ago

OK, I added a new release on the front page (1.4.1). This one will return MMSYSERR_NOERROR to Rekordbox, even if Wine gives an MSMSYSERR_INVALHANDLE.

I would expect that this will at least trigger Rekordbox to then query the device name next. Let's see whether it accepts the result and moves on to actual MIDI communication.

Can you give it a try and report back with the new API monitor log?

elvetemedve commented 2 months ago

Thanks.

It made me thinking that the Midi implementation in Wine must be incomplete. The related wiki page is from 2016, which tells me that it's not actively developed.

I've tried out the new release. Unfortunately I don't see the name in the log or MMSYSERR_NOERROR in API Monitor. It looks like the rule does not match in handle_QUERYDEVICEINTERFACESIZE(), because the text starting with "_Matched a replace rule. Returning MMSYSERRNOERROR with size" is not captured in the log.

See logs.zip

SanderVocke commented 2 months ago

I have to apologize - not having a test setup ready I thought I could get away without testing things a bunch of times and obviously I was wrong about that.

I got a hold of a Windows environment and worked on ironing out some issues. There were multiple logging issues and also an issue that prevented matching rules in some cases.

I still can't promise that this works, as I still don't have a full test setup in the sense that I don't have any app that queries the device interface and does something useful with it. But at least I tested this to the point that I got the wrapper to return the spoofed device interface name. And the logging is a lot more readable now.

Can you try again with the latest release on the front page?

SanderVocke commented 2 months ago

To properly test this feature myself I would need to find an app that queries the device interface name and reports it back to the user somehow, so that I can tell whether it was correctly spoofed.

An app that comes to mind is the midienum.exe that can be found by Googling around. But it only links to the 32-bit version of WinMM.dll, and the one I provide is only 64-bit. I found that it will take a bit of effort to either convert midienum to 64-bit or provide a 32-bit wrapper. Not quite willing yet to invest that time. I hope we can do without that!

As usual, I have high hopes that the latest release does what it is supposed to do. Curious to hear how it goes.

elvetemedve commented 2 months ago

You don't need to apologize. I'm glad that you still put effort into this exploration of the MIDI interface.

I completely agree that having a realistic puppet application for testing takes a lot of work and probably too much effort.

I grabbed the latest release and did the testing. This time faking the API call worked well. :tada: Thank you. :smiley: I can see that Rekordbox queried both the interface size and name via two calls (message 2061, 2060) and both returned MMSYSERR_NOERROR. It's success, though the MIDI messaging still hasn't started yet. Under Windows the next API call is midiInOpen() / midiOutOpen(), but I don't see any of these in the API Monitor capture. Instead of that it seems to be querying the list of devices in a loop.

That made me thinking what does it do with the returned interface name \\?\usb#vid_2b73&pid_0041&mi_03#9&2f46a9a1&0&0003#{6994ad04-93ef-11d0-a3cc-00a0c9223196}\global since it's not the device name. I was thinking that it might look up something in the Registry based on this, so installed the ProcessMonitor tool to inspect that. I found that first it reads the key

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses\{6994ad04-93ef-11d0-a3cc-00a0c9223196}\##?#USB#VID_2B73&PID_0041&MI_03#9&2f46a9a1&0&0003#{6994ad04-93ef-11d0-a3cc-00a0c9223196}\#GLOBAL]

Secondly it reads

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_2B73&PID_0041&MI_03]

Both has a sub-key which holds the key-value pair "FriendlyName"="DDJ-FLX10". I assume that's returned to Rekordbox from one of these places via some other Windows API and listed as a MIDI controller by the application. As a quick try I exported these Registry values and imported it under Wine, but unfortunately didn't make a difference (it might work differently under Wine or not implemented yet).

I will try to find out what is the related Windows API and compare the differences between Wine and Windows.

For now if you curious to see the details, I captured all related logs here: logs.zip

SanderVocke commented 2 months ago

One step further again! Too bad this wasn't enough to get Rekordbox to surrender just yet.

Looks like this is the point where Rekordbox veers off of pure MIDI interfacing and uses these registry keys to directly query information about the underlying USB device. Description by ChatGPT:

The registry entries under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\ in Windows are used to store information about USB devices that have been connected to the system. These entries are crucial for the operating system to manage and interact with USB devices, such as keyboards, mice, storage drives, and other peripherals.

See also: https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-device-specific-registry-settings

It is unclear whether spoofing those registry calls somehow would be sufficient, or some extra USB driver-level stuff is happening to confirm the device is what it thinks it is.

I am not really willing or able to explore this without having the device myself, so indeed I suggest that you look further into it yourself. Probably, whatever the solution it won't be fixable within winmm.dll but would require registry/driver hacks and/or spoofing additional DLLs.

In wine, can you also use ProcessMonitor? You could confirm whether Rekordbox reads those same keys under Wine as well. If not, you could use API monitor to see if there are other Windows API calls Rekordbox is making on Windows before it reads those keys - maybe there is something in-between.

If you do find a solution direction, let's discuss further if that could be made into an additional feature or tool here.

elvetemedve commented 2 months ago

Sorry, I came to the wrong conclusion in my last comment. Actually spoofing the call was enough to try opening connection to the MIDI device. Though midiOutOpen() returned MMSYSERR_NOERROR, unfortunately midiInOpen() returned MMSYSERR_NOTENABLED. I believe that's why Rekordbox started enumerating the devices again.

I have tried to track it down where does that error come from. I believe you are right about the difference between two OSes: winmm utilises the low level Windows drivers, while under Wine it utilises the audio driver (winealsa.drv, winepulse.drv etc.). I tried both Pulse and Alsa, but got the same result.

Digging a bit deeper in the Wine source code, I found that the error comes from the midi_in_open() function (in case of winealsa.drv). Inside that method the call to snd_seq_connect_from() returns an error code. This function belongs to ALSA-Lib, so it looks like the hardware is not fully supported by the ALSA driver. I guess it means faking further winmm API does not really help.

That's how far I've got now. I will look into the ALSA project later to see how they add support for new hardware. I presumed USB MIDI devices are plug-and-play these days, but that's not entirely true.

SanderVocke commented 2 months ago

That's interesting - if those USB-level calls didn't come directly from Rekordbox but from WinMM, maybe there is hope.

That being said, are you sure that this device totally doesn't work on Wine? Pioneer's website states that the DDJ-FLX10 should work fine as a generic MIDI device. Can you try if it works as such under wine, e.g. using https://hautetechnique.com/midi/midiview/? Do you see messages coming in?

If that works, I wonder why it would not work in Rekordbox. It's not like there are significantly different ways to call midiInOpen().

elvetemedve commented 2 months ago

Pioneer's website states that the DDJ-FLX10 should work fine as a generic MIDI device.

I was skeptical about that statement, because they provide proprietary drivers for both Windows and MacOS. So assumed might be true for these supported platforms only.

Hmm. Midi View is able to capture the messages when I push elements on the controller. image

I captured the communication by the API Monitor. Even though the advanced device name query fails, both midi*Open() calls were successful. Midi View - API monitor (Linux).zip

Now I don't understand what's going on. :laughing:

SanderVocke commented 2 months ago

So you ran MidiView without the wrapper DLL, right? It makes sense the name query fails then, and probably MidiView just proceeds to open the interface anyway since it's a debugging tool.

So the main question then is why midiInOpen() would fail with MMSYSERR_NOTENABLED for Rekordbox through the wrapper, while it works fine with MidiView without the wrapper.

One step could be to run MidiView through the wrapper DLL with the same config as Rekordbox, and see if it still works. If not, then the wrapper DLL is somehow causing this to fail. If it does work, Rekordbox is doing something we haven't figured out yet.

elvetemedve commented 2 months ago

So you ran MidiView without the wrapper DLL, right?

Yes, that's correct.

Running it through the wrapper makes a difference. Midi View does not record any message. I don't see neither midiOutOpen(), nor midiInOpen() calls in the log.

Can you think of any change in the wrapper that's related?

image Midi View - winmm 1.4.2 - API monitor (Linux).zip

SanderVocke commented 2 months ago

Hmm, I'll have a closer look after the weekend.

elvetemedve commented 2 months ago

Sorry again. I made a mistake somewhere. I double checked it today and the wrapper works nicely with the Midi View. The name has changed as you can see on the screenshot and it can receive messages from the device. image

So it must be something else that the blocks Rekordbox from using it.

SanderVocke commented 2 months ago

Ah, ok - then I would go back to trying to find out what non-midi USB stuff rekordbox is doing, if any. Tbh I have no clue what windows APIs could be involved. Maybe there are different monitoring tools that could help, geared more towards USB devices?

E.g. https://freeusbanalyzer.com/

elvetemedve commented 2 months ago

Checking the USB level communication is a great idea. I learned some basic stuff about USB as don't know anything about the low level stuff.

I found that the device provides many interfaces, one of them is the MIDI. An interface can have 0 or more endpoints which are the "ports" to communicate with that interface. In this case there are two, one for outbound (PC/host to device) and one inbound (device to PC/host). So I wanted to sniff traffic on this interface to capture communication of both endpoints.

I got a bit lost with the Free USB Analyzer, so ended up using Wireshark for that. The setup went like this under both OS-es:

  1. Unplug the USB cable of the DJ controller.
  2. Start capturing USB traffic (This differs a bit across platforms. On Windows I can select the USB device to capture, but on Linux I can select only the bus, so traffic from other devices might be captured too which needs filtering later).
  3. Started Rekordbox.
  4. Moved few controls on the DJ controller.
  5. Stopped the capturing.

The key part is visible on the screenshot:

USB sniff comparision

To sum up, I need to study this MIDI SysEx (System Exclusive Command) further. Also need to understand how is that linked to the winmm API (or related Windows API). If you have any suggestion, observation then let me know.

SanderVocke commented 2 months ago

Wow, I have to say I admire your dedication on this :) I hope it pays off.

Unfortunately I also don't have much/any knowledge about USB device protocols. All I can do is spar and brainstorm a bit.

I would say that the SysEx could be a difference, but that doesn't mean it is the cause of the issue. After all a SysEx message is still just a MIDI message: to send it, the MIDI interface must first be opened. And if I remember right, on WINE, the midiInOpen() call and/or midiOutOpen() call never came, right?

So my guess is that whatever causes Rekordbox to not open the MIDI device is probably not related to the SysEx message. Probably, that is just what the software will send first if you do get it to open the midi device.

I do see another difference: USB-BULK messages on the left and none of them on the right. Is that true? I think (and ChatGPT confirmed this) that USB BULK is a different protocol than USB MIDI. It is a more low-level serial communication that many USB devices use.

Which brings me back to my earlier guess: that probably, in addition to the MIDI endpoint the device also has a "regular" USB endpoint (the bulk one), and Rekordbox is using it to do some additional communication apart from the MIDI part.

If that is the case, I am afraid this will be very hard to get around, as generic USB support on WINE is as good as nonexistent...

elvetemedve commented 2 months ago

Thanks, me too. This is the first time when I see no glitches on the app UI, furthermore does not crash after interacting with the UI. The audio playback is already working (even without WineASIO). The last missing piece is getting the MIDI interface working. :)

if I remember right, on WINE, the midiInOpen() call and/or midiOutOpen() call never came, right?

Actually, both calls are successful. I'm not sure when/why did that change exactly.

You are right again. Now I think the MIDI communication has not been started on the wire. I wanted to approach this issue from a difference angle, so installed VirtualDJ (which has official support for DDJ-FLX10). VirtualDJ - New Device Detected (Linux) As you can see on the screenshot, the hardware is detected thanks to this wrapper DLL :partying_face:, but also detect that something is missing on the software side.

So I run one more round with API Monitor and found a common failure between the two applications which the call IAudioClient::Stop() indicates by returning AUDCLNT_E_NOT_INITIALIZED. Rekordbix - API Monitor

Maybe this is a hint to find the next missing piece.

SanderVocke commented 2 months ago

That is encouraging and disappointing at the same time!

Please take my words about USB with a grain of salt, because I don't really know what I'm talking about. From a quick Google, it could be USB-BULK is just the underlying protocol that USB-MIDI is implemented on top.

But if VirtualDJ speaks about an extra driver, that is not very encouraging. USB-MIDI works in WINE because it is running on Linux drivers, and just exposed to WINE as virtual MIDI devices. Wine doesn't have to do any actual "USB work", only "MIDI work", and that is also the layer where my DLL operates.

If there is indeed another Windows USB driver involved, you won't be able to install that on WINE, and this DLL won't help. And there probably isn't a Linux driver (unless there is some software on Linux that supports your controller?)

Again, I may very well be wrong, but I'm starting to think that you will not get this working without some serious reverse engineering.

SanderVocke commented 2 months ago

Not to discourage you, but how about taking this in a different direction?

The device probably works as a pure Midi device, even if rekordbox doesn't recognize it for what it really is.

What if you configure rekordbox using the Midi learn options meant for generic Midi controllers?

That way you might be able to get a lot of the controls working. You could use my Dll to rename the device to something completely different, so that rekordbox just sees it as a generic, unknown Midi device.

Just thinking out loud here - I have no idea what kind of fancy features you'd be missing out on by not having the "official" integration.

elvetemedve commented 2 months ago

That's a good idea. Though renaming the device does not make a difference. In order to be able to create a custom mapping for a MIDI controller, it must first show up in the list of connected devices. The MIDI menu is inactive currently, so I can't even open it.

I would be satisfied with that because that would allow testing the app under Wine.

Just thinking out loud here - I have no idea what kind of fancy features you'd be missing out on by not having the "official" integration.

Sure, good thinking. I don't know either why they needed this proprietary driver and still unsure if that's the missing piece at the moment or something Wine related thing. (One such feature I can think of is the built-in LCD display.)

SanderVocke commented 2 months ago

Does the controller work in Linux? As in: do you see it show up as a JACK midi device or alsa midi device, and can you receive signals from it there using some Linux MIDI monitor tool?

If so, then there should be no proprietary driver needed for it to work in Wine (as a generic MIDI controller).

elvetemedve commented 2 months ago

Yes, it does. I've tested it with ALSA utils:

So basic MIDI communication works well out of the box. This tells me that the communication is broken somewhere inside Wine.

SanderVocke commented 2 months ago

And did the MIDI monitor program (for windows) that we used before also work in WINE?

elvetemedve commented 2 months ago

Yes, it did (though I was able to test only the inbound messages). Hmm. I compared the Wine debug messages between MidiView and Rekordbox and found an interesting line which is present only for Rekordbox:

fixme:mmdevapi:control_RegisterAudioSessionNotification (0000000003FB07F0)->(00000000327589A0) - stub

About that method from Microsoft documentation:

The RegisterAudioSessionNotification method registers the client to receive notifications of session events, including changes in the stream state. Through these methods, the client receives notifications of the following session-related events:

Display name changes
Volume level changes
Session state changes (inactive to active, or active to inactive)
Grouping parameter changes
Disconnection of the client from the session (caused by the user removing the audio endpoint device, shutting down the session manager, or changing the stream format)

My assumption is that Rekordbox waits for the display name change or state change event, but it won't be triggered, because the mmdevapi:control_RegisterAudioSessionNotification is not implemented. Do you think this reasoning makes sense?

SanderVocke commented 2 months ago

I don't fully understand that part of the MMdevapi docs. But to me it sounds like an interface that has to do with the entire session, not just a MIDI device.

In other words, I would expect that if this call is the reason, then the entire Rekordbox session wouldn't work. Is that the case? Can you use Rekordbox normally with just your mouse and keyboard?

You may be on the right track but I really don't know. I do think there is one more thing you could try: Do you have any other MIDI devices lying around - generic ones? Can you use those in Rekordbox in Wine?

The reason I suggested to change the name of the DJ controller to something else is that I hoped rekordbox would just see it as a regular device. If another device works, I don't see why the DJ controller wouldn't.