问题
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