Android - 用 MIDI 文件播放 SoundFont
Android - Play SoundFont with MIDI file
我有一个 midi 文件,我在 android 中使用 MediaPlayer 播放了该 midi 文件,代码如下:
val mMediaPlayer = MediaPlayer.create(context, R.raw.test_ring_1)
mMediaPlayer?.start()
它默认使用一种乐器演奏,例如钢琴,现在我想添加 soundfont (sf2/sf3) 文件以使用不同乐器和混响效果演奏 midi 音符。
请指导如何达到预期效果。
我已经测试过它可以正常工作
@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;
}
});
}
不要忘记从下面的存储库中包含 sherlockmidi 库,下面的存储库中也提供了示例。
有两个库将用于使用 SoundFont 播放 midi 文件。
只是一个用于在 Android 上播放 MIDI 音符的合成器。您可以将它与 USB/Bluetooth-MIDI 库一起使用来创建您的 MIDI 应用程序。
支持 SoundFont2 文件。
这个库提供了一个接口来读取、操作和写入 MIDI 文件。 "Playback" 支持作为 real-time 事件调度系统。此库不包括实际的音频播放或设备接口。
初始化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();
从 midi 文件播放 Midi 音符
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();
定义SF通道的变量
private int channel = 0;
我有一个 midi 文件,我在 android 中使用 MediaPlayer 播放了该 midi 文件,代码如下:
val mMediaPlayer = MediaPlayer.create(context, R.raw.test_ring_1)
mMediaPlayer?.start()
它默认使用一种乐器演奏,例如钢琴,现在我想添加 soundfont (sf2/sf3) 文件以使用不同乐器和混响效果演奏 midi 音符。
请指导如何达到预期效果。
我已经测试过它可以正常工作
@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;
}
});
}
不要忘记从下面的存储库中包含 sherlockmidi 库,下面的存储库中也提供了示例。
有两个库将用于使用 SoundFont 播放 midi 文件。
只是一个用于在 Android 上播放 MIDI 音符的合成器。您可以将它与 USB/Bluetooth-MIDI 库一起使用来创建您的 MIDI 应用程序。
支持 SoundFont2 文件。
这个库提供了一个接口来读取、操作和写入 MIDI 文件。 "Playback" 支持作为 real-time 事件调度系统。此库不包括实际的音频播放或设备接口。
初始化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();
从 midi 文件播放 Midi 音符
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();
定义SF通道的变量
private int channel = 0;