Android - Play SoundFont with MIDI file

冷暖自知 提交于 2020-01-22 14:37:25

问题


I have one midi file and I have played that midi file using MediaPlayer in android using the following code:

val mMediaPlayer = MediaPlayer.create(context, R.raw.test_ring_1)

mMediaPlayer?.start()

It default play with one instrument like piano, now I want to add soundfont (sf2/sf3) file to play the midi notes with different instrument and with reverberation effects.

Please guide a way to achieve expected result.


回答1:


There are two libraries that will be used to play a midi file using SoundFont.

Midi Driver

Just a synthesizer for playing MIDI note on Android. You can use it with USB/Bluetooth-MIDI library together to create your MIDI application.

SoundFont2 file is supported.

Android MIDI Library

This library provides an interface to read, manipulate, and write MIDI files. "Playback" is supported as a real-time event dispatch system. This library does NOT include actual audio playback or device interfacing.

To initialize SF2-SoundBank

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();

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();

Variable to define SF channel

private int channel = 0;



回答2:


I have tested this it is working

    @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    try {
        SF2Soundbank sf = new SF2Soundbank(getAssets().open("SmallTimGM6mb.sf2"));
        synth = new SoftSynthesizer();
        synth.open();
        synth.loadAllInstruments(sf);
        synth.getChannels()[0].programChange(0);
        synth.getChannels()[1].programChange(1);
        recv = synth.getReceiver();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (MidiUnavailableException e) {
        e.printStackTrace();
    }


    this.findViewById(R.id.piano).setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            int action = MotionEventCompat.getActionMasked(event);
            if (action == MotionEvent.ACTION_DOWN) {
                try {
                    ShortMessage msg = new ShortMessage();
                    msg.setMessage(ShortMessage.NOTE_ON, 0, 60, 127);
                    recv.send(msg, -1);
                } catch (InvalidMidiDataException e) {
                    e.printStackTrace();
                }
            } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
                try {
                    ShortMessage msg = new ShortMessage();
                    msg.setMessage(ShortMessage.NOTE_OFF, 0, 60, 127);
                    recv.send(msg, -1);
                } catch (InvalidMidiDataException e) {
                    e.printStackTrace();
                }
            }
            return true;
        }
    });

    this.findViewById(R.id.woodblock).setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            int action = MotionEventCompat.getActionMasked(event);
            if (action == MotionEvent.ACTION_DOWN) {
                try {
                    ShortMessage msg = new ShortMessage();
                    msg.setMessage(ShortMessage.NOTE_ON, 1, 60, 127);
                    recv.send(msg, -1);
                } catch (InvalidMidiDataException e) {
                    e.printStackTrace();
                }
            } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
                try {
                    ShortMessage msg = new ShortMessage();
                    msg.setMessage(ShortMessage.NOTE_OFF, 1, 60, 127);
                    recv.send(msg, -1);
                } catch (InvalidMidiDataException e) {
                    e.printStackTrace();
                }
            }
            return true;
        }
    });
}

Dont forget to include sherlockmidi library from below repository, sample is also available in below repository.

https://github.com/agangzz/SherlockMidi



来源:https://stackoverflow.com/questions/56541361/android-play-soundfont-with-midi-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!