GithubHelp home page GithubHelp logo

android-midi-lib's People

Contributors

leffelmania avatar raltamirano avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

android-midi-lib's Issues

choose Instrument

Hi Alex,

I'm working on a little project and your android-midi-lib is helping out a lot!

I think that there is an important feature missing though, which is the ability to specify a midi-instrument for a chanel. Or did I just miss the right method?

Anyways thanks a lot for your effort :)
Kind regards

MidiProcessor set current tick

Add seek(tick) method in MidiProcessor class. It will set play time to another tick and dispatch all events before current tick.Please to implement it,thank you!

Potential off by one in ChannelEvent Channel field

I think there's an off by one error in the channel for ChannelEvent objects. I know drums are always supposed to be on channel 10 but in the lib it comes back as 9. Cross referenced this with my DAW

How to play all instruments of a midi file?

I already use the MIDI driver and Android MIDI library to play MIDI with Soundfont on Android. It works, but I only hear the piano. Even though my soundfont & midi file consists of many instruments, not just piano.

private int channel = 0;

SF2Soundbank sf = new SF2Soundbank(getAssets().open("test.sf2"));
        synth = new SoftSynthesizer();
        synth.open();
        synth.loadAllInstruments(sf);
        synth.getChannels()[0].programChange(0);
        synth.getChannels()[1].programChange(1);
        recv = synth.getReceiver();

        synth.getChannels()[1].programChange(1);
        recv = synth.getReceiver();

//To Play the Midi notes from midi file

MidiFile midiFile = new MidiFile(getAssets().open("test.mid"));

// Create a new MidiProcessor:
MidiProcessor processor = new MidiProcessor(midiFile);

// listen for all midi events:
processor.registerEventListener(new MidiEventListener() {
    @Override
    public void onStart(boolean fromBeginning) {

    }

    @Override
    public void onEvent(MidiEvent event, long ms) {

        if (event.getClass() == NoteOn.class) {

                NoteOn noteOn = ((NoteOn) event);

                try {
                    ShortMessage msg = new ShortMessage();
                    msg.setMessage(ShortMessage.NOTE_ON, channel, noteOn.getNoteValue(), noteOn.getVelocity());
                    recv.send(msg, ms);
                } catch (InvalidMidiDataException e) {
                    e.printStackTrace();
                }

            } else if (event.getClass() == NoteOff.class) {

                NoteOff noteOff = ((NoteOff) event);

                try {
                    ShortMessage msg = new ShortMessage();
                    msg.setMessage(ShortMessage.NOTE_ON, channel, noteOff.getNoteValue(), noteOff.getVelocity());
                    recv.send(msg, ms);
                } catch (InvalidMidiDataException e) {
                    e.printStackTrace();
                }

            }
    }

    @Override
    public void onStop(boolean finished) {

    }
}, MidiEvent.class);

// Start the processor:
processor.start();

Midi rookie wants to Integrate midi-lib with other APP

Hi Alex,

Your code is inspiring, so please forgive my stupid questions.

I've run the sample code on PC, and plan to integrate the midi library
with other Midi Sheet music APP which generate midi sound and the midi library will send midi event to external midi device thru bluetooth interface at the same time.

Question #1

The example"Event Printer" show the parsed midi event on screen.
Can I just add my code "SENT TO BLUETOOTH INTERFACE" as below or other
modifications are needed? such as tempo,speed...

public void onEvent(MidiEvent event, long ms)

    //System.out.println(mLabel + " received event: " + event);
    "SENT TO BLUETOOTH INTERFACE"
}

Question #2
Can I just import the android-midi-libv3-49.jar file and use it in Eclipse ADT?

Thank you in advance for your time
Regards,

MidiUtil.bpmToMpqn() Method Error

resource code is:

    public static int bpmToMpqn(float bpm) {
        return (int)(bpm * 6.0E7F);
    }

I think it should be

    public static int bpmToMpqn(float bpm) {
        return (int)( 6.0E7F / bpm);
    }

How to move process.start() process back and forward?

Hello,

I am trying to implement a Midi player with << and >> buttons.

Is there a way you can rewind the process and make it go faster to seek a possition in the midi file?

// Register for the events you're interested in:
EventPrinter ep = new EventPrinter("Individual Listener");
processor.registerEventListener(ep, NoteOn.class);

// Start the processor:
processor.start();

Thanks in advance!

Accessing 'raw' Midi event data from a midi event object.

I wanted to adapt the event printer example to actually send a file to a midi device... This is going just fine, except accessing the actual raw midi data from the event...

The event printer says what the event is, but not which channel etc... Ideally accessing the original bytes read from the midi file to create the event object would do the job - but despite a lot of looking, I haven't been able to get my head around your variable length int stuff(!).

VariableLengthInt does not set bit 7 when parsing inputStream

I noticed that VariableLengthInts do not set the 7th bit on any byte in the parseBytes() function. This can be fixed easily by droping the & operation in line 78 resulting in
ints[mSizeInBytes - 1] = b;

To account this change line 93 must be changed to ensure mValue is correctly calculated
mValue += (ints[i] & 0x7F) << shift;

And by the way why don't you set shift (line83-86) simply by
int shift = (mSizeInBytes-1)*7;
saves another for loop ;)

Events are dropped when reading in MidiFile

Context

It is perfectly valid for a MidiFile to contain two noteOns followed by two noteOffs:

tick : event
0    : NoteOn channel 0 key 66 vel 100
1000 : NoteOn channel 0 key 66 vel 100
2000 : NoteOff channel 0 key 66
2000 : NoteOff channel 0 key 66 

It is up to the synthesizer to decide whether it wants to voice this as two notes or not. Here's what the spec has to say:

ASSIGNMENT OF NOTE ON/OFF COMMANDS
If an instrument receives two or more Note On messages with the same key number and MIDI channel, it must make a determination of how to handle the additional Note Ons. It is up to the receiver as to whether the same voice or another voice will be sounded, or if the messages will be ignored. The transmitter, however, must send a corresponding Note Off message for every Note On sent. If the transmitter were to send only one Note Off message, and if the receiver in fact assigned the two Note On messages to different voices, then one note would linger. Since there is no harm or negative side effect in sending redundant Note Off messages this is the recommended practice.

The important thing here is that we need the same number of NoteOffs as NoteOns, otherwise some synthesizers may have a lingering note.

Problem

Some MIDI files, when read by this library, will drop one of these NoteOffs. This is because each track stores its events in a TreeSet, so if two events are "equal" (due to the implementation of Comparable), only one can be stored. This is a bug because perfectly valid MIDI files can cause this to happen, resulting in more NoteOns than NoteOffs, resulting in a lingering note on some (valid) synthesizers.

Reproduction

As a pathological example, the following code (Kotlin) throws an exception (i.e. the error code was run).

val noteTrack = MidiTrack()
noteTrack.insertEvent(NoteOff(0, 0, 66, 64))
noteTrack.insertEvent(NoteOff(0, 0, 66, 64))
if (noteTrack.eventCount != 2) error("One event was dropped")

A more realistic example is as follows. This produces a lingering note on my synthesizer.

private fun generateMidiFile(): MidiFile {
        val tempoTrack = MidiTrack()
        val noteTrack = MidiTrack()

        val ts = TimeSignature()
        ts.setTimeSignature(
            4,
            4,
            TimeSignature.DEFAULT_METER,
            TimeSignature.DEFAULT_DIVISION
        )
        val tempo = Tempo()
        tempo.bpm = 228f

        tempoTrack.insertEvent(ts)
        tempoTrack.insertEvent(tempo)

        noteTrack.insertEvent(ProgramChange(0, 0, 0))

        // Two noteOns - some synthesizers choose to play 2 voices here
        noteTrack.insertEvent(NoteOn(0, 0, 66, 80))
        noteTrack.insertEvent(NoteOn(1000, 0, 66, 100))

        // Two simultaneous noteOffs and an unrelated noteOn at the same time.
        // The first noteOff will be replaced by the second, leaving one more noteOn
        // than noteOff.
        noteTrack.insertEvent(NoteOn(2000, 0, 73, 100))
        noteTrack.insertEvent(NoteOff(2000, 0, 66, 64))
        noteTrack.insertEvent(NoteOff(2000, 0, 66, 64))

        // Kill the unrelated note
        noteTrack.insertEvent(NoteOff(2500, 0, 73, 64))

        // Long pause to hear the ringing, then another note to end the file
        noteTrack.insertEvent(NoteOn(10000, 0, 73, 100))
        noteTrack.insertEvent(NoteOff(11000, 0, 73, 64))

        val tracks: MutableList<MidiTrack> = ArrayList()
        tracks.add(tempoTrack)
        tracks.add(noteTrack)

        return MidiFile(MidiFile.DEFAULT_RESOLUTION, tracks)
    }

And here is how it sounds on my synthesizer (using the violin preset so we can hear the lingering notes):

LingeringNote.mp4

Here's how these MIDI notes should sound (this was achieved by tweaking the velocity of one of the NoteOffs so they weren't equal):

HowItShouldSound.mp4

Fix ideas

I think it's surprising that a set (in this case, a TreeSet) is used to store the events for a track, since you run into exactly this problem with sets (they cannot hold several identical objects). Moreover, it is prudent to remember the order that events were added, even if they occur on the same tick, as you should really honour the order they appeared in the file (e.g. the difference between NoteOn then simultaneous NoteOff, vs NoteOff then simultaneous NoteOn - they may sounds different). So I really think that a simple array or list is a more sensible data structure.

Alternatively, consider having some way to distinguish (i.e. order) two otherwise identical events. Maybe every event gets given some extra integer property tracking the order it was added to the track. This way, we can order two otherwise identical events, so they don't overwrite each other.

Format 2?

will this be updated to allow format 2 MIDI?

Default Instrument

Hi, i don't understand where is set the default instrument used for composing Track and file.

How to calculate tick?

NoteOff off = new NoteOff(tick, channel, pitch, 0);

When receive onSend(byte[] data, int offset, int count, long timestamp) event, we only know the event's timestamp, how to use timestamp to get tick? Timestamp is system's nano time

Bug in compareTo()

Hi Alex,

In class KeySignature, line 120, method compareTo(), it seems you are comparing a key against an scale by mistake. I think you want to compare a scale against another scale.

Regards

Start midi play from specific time

Hello,
I need implement a loop button control in my aplication. Its possible start and stop a midi play from an specific time. ?
Thanks

create midi file with chords

Hi Alex,
I'm working on my own project to create a midi file with the help of your midi-lib.
And I'm facing up to writing midi file if note is a chord.
Could you suggest me any idea to solve my problem? Or I missed the right method?
Thanks for you effort.

License issue

LICENSE files states "MIT" but file headers states "Apache 2.0".

How to handle Pitch Bend ?

Just figured this out.
While the event listener listens for MidiEvents, most of them are also ChannelEvents, which is an detention of MidiEvent. The ChannelEvents have the info you need to load the channels of your synth.

Here is an example in Kotlin, within the onEvent callback.

                var channel = 0
                if(event is ChannelEvent){
                    Log.i("ChannelEvent", "${event.getChannel()}")
                    channel = event.channel
                }
                if (event is ProgramChange){
                    synth.channels[event.channel].programChange(event.programNumber)
                }

The ProgramChange event has the channel number and instrument voice to load your synth.

How to handle Pitch Bend in Event Listener?

Originally posted by @ghopretz in #25 (comment)

Error at MidiTrack insertNote

public class MidiTrack {
    ...
    this.insertEvent(new NoteOn(tick, channel, pitch, velocity));
    this.insertEvent(new NoteOn(tick + duration, channel, pitch, 0));
    ...

should be

public class MidiTrack {
    ...
    this.insertEvent(new NoteOn(tick, channel, pitch, velocity));
    this.insertEvent(new NoteOff(tick + duration, channel, pitch, 0));
    ...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.