我将不胜感激您对随附的源代码/问题的想法。
下面的代码适用于大多数 MIDI 文件。但是,有些声音不正确。
它们会产生一种哇-哇的声音。我能够通过修改 Java StandardMidiFileReader 以删除 176/1/77/0 消息(颤音深度)来规避纯钢琴曲的问题,例如下面使用的曲子。
有人知道如何真正解决这个问题吗?这不仅仅是一首音乐。
我相信 Gervill 可能存在错误,例如类路径上的 Gervill(或 Java 7,其中 Gervill 似乎是发行版的一部分(并且我刚刚发现当前的 Java 6 版本))某些其他文件无法正确播放一点也不。一个例子是http://mb-s2.sakura.ne.jp/tirol/junk/midi/wagner_walkurenritt.mid
(从大约 20 秒开始,当 Gervill 被使用时,同样有趣的 Wha-Wha 背景噪音开始)
通过替换标准合成器与 Keishi Suenaga 的 Timidity++ 扩展版本并使用相同的 SF2,所有部分听起来都很好,所以它不会损坏 MIDI 文件。
代码:对于 Java SF2 支持 Gervill 需要在类路径
Soundfont:我已经尝试过 JCLIVE.SF2 和一个 Steinway SF2;
soundfonts 可以在hammersound.net 或synthfont.com 上获得 sfarc
unpacker 可以从 melodymachine.com 下载,或者如果站点关闭 sourceforge.net/projects/miditool/files/third%20party/
package test;
import java.io.File;
import java.io.FileInputStream;
import javax.sound.midi.Instrument;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Soundbank;
import javax.sound.midi.Synthesizer;
import com.sun.media.sound.SF2Soundbank;
public class SF2Test2 {
static Synthesizer synthesizer;
static Sequencer sequencer;
static MidiDevice dev;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
synthesizer=MidiSystem.getSynthesizer();
synthesizer.open();
// soundbank =synthesizer.getDefaultSoundbank();
// p("Soundbank: " + soundbank.getName() + " / " + soundbank.getDescription()+ " / " + soundbank.getVendor());
}
catch (Exception e) {e.printStackTrace();}
loadSF2();
File f = new File("D:\\SF2\\rach.mid"); //http://mb-s2.sakura.ne.jp/tirol/junk/midi/rachmaninoff_op3_2.mid
play(f);
}
private static void loadSF2() {
String filename;
boolean duringInitialLoad=false;
try{
filename="D:/SF2/JC.SF2";
File f= new File(filename);
if(f.exists()){
Soundbank soundbank=new SF2Soundbank(
new FileInputStream(f));
synthesizer.loadAllInstruments(soundbank);
//synthesizer.open();
//moving open command to here: synthesizer will still run on default (Gervill) soundbank
p("\n now loaded on synthesizer: ");
printInstruments(soundbank,synthesizer.getLoadedInstruments());
}
else {
p(filename + " not found");
System.exit(0);
}
}catch(Exception e){
e.printStackTrace();
}
}
private static void play(File file){
try {
sequencer=MidiSystem.getSequencer();
Sequence sequence= MidiSystem.getSequence(file);
sequencer.setSequence(sequence);
sequencer.open();
sequencer.getTransmitter().setReceiver(synthesizer.getReceiver());
p("starting Sequence...");
sequencer.start();
Thread.sleep(15000);
sequencer.stop();
sequencer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void printInstruments(Soundbank soundbank,Instrument[] instruments){
p("");
p("----------------------------------------------------------------------------");
p("Soundbank name: " + soundbank.getName());
p("Soundbank version: " + soundbank.getVersion());
p("Description: " + soundbank.getDescription());
p("Author: " + soundbank.getVendor() + ".");
p("Number of instruments: " + soundbank.getInstruments().length);
for (Instrument i : instruments)
{
p( "Bank=" + i.getPatch().getBank() +
" Patch=" + i.getPatch().getProgram() +
" Instr.=" + i);
}
}
public static void p(Object o){
System.out.println(o);
}
}
我还尝试将 SF2 声音文件中的单个乐器加载到合成器上,我不依赖 com.sun.media.sound.SF2Soundbank 类,结果相同:
try{
filename="D:/SF2/JCLIVE.SF2";
File f= new File(filename);
if(f.exists()){
Soundbank soundbank=MidiSystem.getSoundbank(f);
Instrument [] sf2Instruments = soundbank.getInstruments();
Instrument [] newInstruments = new Instrument[128];
int replaced=0;
//load pianos only
for(int i=0;i<3;i++){
try{
int num=sf2Instruments[i].getPatch().getProgram();
newInstruments[i]=sf2Instruments[num];
synthesizer.loadInstrument(sf2Instruments[num]);
replaced++;
}catch(Exception e){}
}
//synthesizer.loadAllInstruments(soundbank);
p("\nreplaced: "+ replaced);
p("\n now loaded on synthesizer: ");
printInstruments(soundbank,synthesizer.getLoadedInstruments());
}
}catch(Exception e){
e.printStackTrace();
}