On Sun, 29 Oct 2023 14:29:45 GMT, Alec Su <d...@openjdk.org> wrote:

>> JVM attempts to reuse the buffer for sending MIDI out data when the buffer 
>> size is enough. It use `dwBytesRecorded` in `MIDIHDR` structure to indicate 
>> the actual size of the data. However, `midiOutLongMsg()` ignores 
>> `dwBytesRecorded`, although it did not mentioned in the documentation. I've 
>> tested on Windows 7, 10 and 11. All of them have the same behavior.
>> 
>> The bug cannot be easily reproduced because some MIDI drivers filter out any 
>> malformed MIDI data. The example code below create a special case to make 
>> sure all MIDI data are legally when the bug is triggered.
>> 
>> 
>> import javax.sound.midi.*;
>> 
>> public class MidiTest {
>>     public static class RawMidiMessage extends MidiMessage {
>>         public RawMidiMessage(byte[] data) {
>>             super(data);
>>         }
>> 
>>         @Override
>>         public Object clone() {
>>             return new RawMidiMessage(this.getMessage());
>>         }
>>     }
>> 
>>     public static void main(String[] args) {
>>         var deviceInfos = MidiSystem.getMidiDeviceInfo();
>>         for (var info : deviceInfos) {
>>             try (MidiDevice device = MidiSystem.getMidiDevice(info)) {
>>                 if (device.getMaxReceivers() != 0) {
>>                     System.out.println("Open MIDI port: " + info.getName());
>>                     device.open();
>>                     Receiver receiver = device.getReceiver();
>>                     // Send two sysex messages at once
>>                     receiver.send(new RawMidiMessage(new byte[]{
>>                             (byte) 0xF0, 0x7D, 0x01, (byte) 0xF7,
>>                             (byte) 0xF0, 0x7D, 0x02, (byte) 0xF7
>>                         }), -1);
>>                     // Send another sysex message
>>                     receiver.send(new RawMidiMessage(new byte[]{(byte) 0xF0, 
>> 0x7D, 0x03, (byte) 0xF7}), -1);
>>                 }
>>             } catch (MidiUnavailableException e) {
>>                 e.printStackTrace();
>>             }
>>         }
>>     }
>> }
>> 
>> 
>> The expected messages received should be the following three messages
>> 
>> F0 7D 01 F7
>> F0 7D 02 F7
>> F0 7D 03 F7
>> 
>> 
>> But acually four messages was received with the second message repeated 
>> twice.
>> 
>> F0 7D 01 F7
>> F0 7D 02 F7
>> F0 7D 03 F7
>> F0 7D 02 F7
>> 
>> 
>> To resolve the issue, I add a new variable to backup the actual buffer size 
>> and set `dwBufferLength` of `MIDIHDR` structure to the size of MIDI data. 
>> After calling `midiOutLongMsg()`, I restore the original buffer size if the 
>> buf...
>
> Alec Su has updated the pull request incrementally with one additional commit 
> since the last revision:
> 
>   Code cleanup

> It use `dwBytesRecorded` in `MIDIHDR` structure to indicate the actual size 
> of the data
> However, `midiOutLongMsg()` ignores `dwBytesRecorded`, although it did not 
> mentioned in the documentation.


This seems to be documented by Microsoft only in the most obscure fashion.

If you look at the doc for midiOutPrepareHeader
https://learn.microsoft.com/en-us/previous-versions/dd798477(v=vs.85)
it says "Before calling the function, set the lpData, dwBufferLength, and 
dwFlags members of the 
[MIDIHDR](https://learn.microsoft.com/en-us/previous-versions/dd798449(v=vs.85))
 structure"

So no mention of dwBytesRecorded.

WAVEHDR is a very similar struct to MIDIHDR and if you look at this WAVEHDR doc 
it says

https://learn.microsoft.com/en-us/previous-versions/dd743837(v=vs.85)

    dwBytesRecorded
    When the header is used in input, specifies how much data is in the buffer.

So I infer the same is true for MIDI

Therefore dwBytesRecorded is only used for input and dwBufferLength is what's 
important for output.

-------------

PR Comment: https://git.openjdk.org/jdk/pull/16399#issuecomment-1786077861

Reply via email to