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

Missing Midi Events #61

Open
Sola85 opened this issue Mar 16, 2017 · 6 comments
Open

Missing Midi Events #61

Sola85 opened this issue Mar 16, 2017 · 6 comments

Comments

@Sola85
Copy link

Sola85 commented Mar 16, 2017

The library does not seem to register every singe midi event. I was using this library to write a visualisation app and I noticed some notes either did not appear at all or got stuck "on" after some time. Upon not being able to find the bug in my own code, I simply added a small counter to the original source code provided here on Github. This counter keeps track of the number of total midi events sent per note. Obviously the counter values should always be even numbers when no key is being pressed, as an "on" event is always followed by an "off" event. However, after playing a few bars of music, the counter values on some notes became odd numbers, indicating that some events were missed.

I have tested this with three different Android devices (Android 5.0, 5.1 and 7.1) and with two different Yamaha instruments (both having a VendorId of 1177). Other market apps do not have this problem which leads me to the conclusion that the problem lies in this library

@trcolgrove
Copy link

trcolgrove commented Oct 9, 2017

This is also an issue with my app (I am developing on nexus 9). The issue does not occur on version 0.1.2, so for anyone experiencing this problem you can revert to that version (have not tested 0.1.3)

in your repositories:

maven {
   url 'https://github.com/kshoji/USB-MIDI-Driver/raw/master/MIDIDriver/snapshots'
}
mavenCentral()

in your dependencies:
compile 'jp.kshoji:midi-driver:0.1.2:@aar'
(a little different than the install for the current version)

amitayd added a commit to joytunes/USB-MIDI-Driver that referenced this issue Dec 10, 2017
Should fix MIDI events being dropped occasionally. (issue kshoji#61)
@Gilianp
Copy link

Gilianp commented Dec 11, 2017

By increasing timeout in bulkTransfer fix the problem for me. Thanks @amitayd. @trcolgrove said that 0.1.2 version works nice, and in this version, the timeout is 0 (infinite). Make sense!

@jrl290
Copy link

jrl290 commented Sep 10, 2018

I've been having dropped messages still, but I've also been having the same trouble with the official Android API. Of course, in Google's example app, they wrap the MidiReceiver class with a custom MidiFramer class. My guess is that Android will group messages together and the callback only sees the one. Here's the MidiFramer code:

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.common.midi;

import android.media.midi.MidiReceiver;
import android.util.Log;

import java.io.IOException;

/**
 * Convert stream of arbitrary MIDI bytes into discrete messages.
 *
 * Parses the incoming bytes and then posts individual messages to the receiver
 * specified in the constructor. Short messages of 1-3 bytes will be complete.
 * System Exclusive messages may be posted in pieces.
 *
 * Resolves Running Status and interleaved System Real-Time messages.
 */
public class MidiFramer extends MidiReceiver {
    private MidiReceiver mReceiver;
    private byte[] mBuffer = new byte[3];
    private int mCount;
    private byte mRunningStatus;
    private int mNeeded;
    private boolean mInSysEx;

    public MidiFramer(MidiReceiver receiver) {
        mReceiver = receiver;
    }

    /*
     * @see android.midi.MidiReceiver#onSend(byte[], int, int, long)
     */
    @Override
    public void onSend(byte[] data, int offset, int count, long timestamp)
            throws IOException {
        int sysExStartOffset = (mInSysEx ? offset : -1);

        for (int i = 0; i < count; i++) {
            final byte currentByte = data[offset];
            final int currentInt = currentByte & 0xFF;
            if (currentInt >= 0x80) { // status byte?
                if (currentInt < 0xF0) { // channel message?
                    mRunningStatus = currentByte;
                    mCount = 1;
                    mNeeded = MidiConstants.getBytesPerMessage(currentByte) - 1;
                } else if (currentInt < 0xF8) { // system common?
                    if (currentInt == 0xF0 /* SysEx Start */) {
                        // Log.i(TAG, "SysEx Start");
                        mInSysEx = true;
                        sysExStartOffset = offset;
                    } else if (currentInt == 0xF7 /* SysEx End */) {
                        // Log.i(TAG, "SysEx End");
                        if (mInSysEx) {
                            mReceiver.send(data, sysExStartOffset,
                                offset - sysExStartOffset + 1, timestamp);
                            mInSysEx = false;
                            sysExStartOffset = -1;
                        }
                    } else {
                        mBuffer[0] = currentByte;
                        mRunningStatus = 0;
                        mCount = 1;
                        mNeeded = MidiConstants.getBytesPerMessage(currentByte) - 1;
                    }
                } else { // real-time?
                    // Single byte message interleaved with other data.
                    if (mInSysEx) {
                        mReceiver.send(data, sysExStartOffset,
                                offset - sysExStartOffset, timestamp);
                        sysExStartOffset = offset + 1;
                    }
                    mReceiver.send(data, offset, 1, timestamp);
                }
            } else { // data byte
                if (!mInSysEx) {
                    mBuffer[mCount++] = currentByte;
                    if (--mNeeded == 0) {
                        if (mRunningStatus != 0) {
                            mBuffer[0] = mRunningStatus;
                        }
                        mReceiver.send(mBuffer, 0, mCount, timestamp);
                        mNeeded = MidiConstants.getBytesPerMessage(mBuffer[0]) - 1;
                        mCount = 1;
                    }
                }
            }
            ++offset;
        }

        // send any accumulatedSysEx data
        if (sysExStartOffset >= 0 && sysExStartOffset < offset) {
            mReceiver.send(data, sysExStartOffset,
                    offset - sysExStartOffset, timestamp);
        }
    }

}

michaelknoch pushed a commit to flowkey/USB-MIDI-Driver that referenced this issue Jan 28, 2020
* overhaul MIDIOutConnection (no protocol)
* add LightController API
@renetik
Copy link

renetik commented Jan 23, 2022

@jrl290 I am also having issues with missing midi events and cannot find the cause... I am using standard android impl and tried also this lib but cannot get it to work. Notes get missing just when I send a lot of them from sequencer . When I play just one track everything is fine I play two almost no missing just sometimes, I play 3 they get lost regularly.. Is it possible that android just cannot send it in time so it just discards them ? Maybe this is not even possible to play midi by USB to some daw on computer ? Its hard to believe it has to be some my issue for sure but when I play locally in app these some midi events in synth are perfect. Little lost sorry if I am off topic here...

@jrl290
Copy link

jrl290 commented Jan 23, 2022

@jrl290 I am also having issues with missing midi events and cannot find the cause... I am using standard android impl and tried also this lib but cannot get it to work. Notes get missing just when I send a lot of them from sequencer . When I play just one track everything is fine I play two almost no missing just sometimes, I play 3 they get lost regularly.. Is it possible that android just cannot send it in time so it just discards them ? Maybe this is not even possible to play midi by USB to some daw on computer ? Its hard to believe it has to be some my issue for sure but when I play locally in app these some midi events in synth are perfect. Little lost sorry if I am off topic here...

When I tailored the MidiFramer code above to the app I was working on, I didn't have any further trouble dropping messages. That was using Android's standard implementation however. I did not end up using this library

@momocoQAQ
Copy link

@jrl290 I am also having issues with missing midi events and cannot find the cause... I am using standard android impl and tried also this lib but cannot get it to work. Notes get missing just when I send a lot of them from sequencer . When I play just one track everything is fine I play two almost no missing just sometimes, I play 3 they get lost regularly.. Is it possible that android just cannot send it in time so it just discards them ? Maybe this is not even possible to play midi by USB to some daw on computer ? Its hard to believe it has to be some my issue for sure but when I play locally in app these some midi events in synth are perfect. Little lost sorry if I am off topic here...

When I tailored the MidiFramer code above to the app I was working on, I didn't have any further trouble dropping messages. That was using Android's standard implementation however. I did not end up using this library

What library did you end up using, is there a library that does the same thing as mido in python on the android? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants