【发布时间】:2015-10-18 19:44:52
【问题描述】:
我已尝试查找有关此的任何信息,但找不到任何有用的信息。
我正在尝试制作一个程序,该程序可以生成一个 midi 文件,该文件由同时使用不同乐器(程序)演奏的两种乐器组成。我一直在使用示例程序: http://www.cs.cornell.edu/courses/cs211/2008sp/examples/MidiSynth.java.txt 作为模板,但是当我尝试人工创建 midi 事件(而不是在示例程序中使用合成器动态生成它们)时,生成的 midi 文件似乎并不关心我是否已经切换程序,使用文件中每个音符的最后更改为程序,由两个 MIDI 轨道组成,即使我已将程序更改数据保存到两个轨道。我已经为我的程序粘贴了代码:
import java.io.File;
import java.io.IOException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Soundbank;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.Instrument;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Track;
import javax.sound.midi.InvalidMidiDataException;
public class MidiTest2
{
/* This velocity is used for all notes.
*/
private static final int VELOCITY = 64;
final int PROGRAM = 192;
final int NOTEON = 144;
final int NOTEOFF = 128;
long startTime;
Sequence sequence;
Synthesizer synthesizer;
Sequencer sequencer;
Instrument instruments[];
ChannelData channels[];
ChannelData cc;
//int instrumentCounter = 0;
Track track;
MidiTest2(){
try{
if(synthesizer == null){
if((synthesizer = MidiSystem.getSynthesizer()) == null){
System.out.println("getSynthesizer() failed");
return;
}
}
synthesizer.open();
sequencer = MidiSystem.getSequencer();
sequence = new Sequence(Sequence.PPQ, 10);
}catch(Exception e){
e.printStackTrace();
return;
}
Soundbank sb = synthesizer.getDefaultSoundbank();
if(sb != null){
instruments = synthesizer.getDefaultSoundbank().getInstruments();
synthesizer.loadInstrument(instruments[0]);
}
MidiChannel midiChannels[] = synthesizer.getChannels();
channels = new ChannelData[midiChannels.length];
for(int i = 0; i < channels.length;++i){
channels[i] = new ChannelData(midiChannels[i], i);
}
cc = channels[0];
}
public void createShortEvent(int type, int num){
ShortMessage message = new ShortMessage();
try{
long millis = System.currentTimeMillis() - startTime;
long tick = millis * sequence.getResolution() / 500;
message.setMessage(type+cc.num, num, cc.velocity);
System.out.println("Type: " + message.getCommand() + ", Data1: " + message.getData1() + ", Data2: " + message.getData2() + ", Tick: " + tick);
MidiEvent event = new MidiEvent(message, tick);
track.add(event);
}catch (Exception e){
e.printStackTrace();
}
}
public void createShortEvent(int type, int num, int eventTime){
ShortMessage message = new ShortMessage();
try{
//long millis = System.currentTimeMillis() - startTime;
long tick = eventTime * sequence.getResolution();
message.setMessage(type+cc.num, num, cc.velocity);
System.out.println("Type: " + message.getCommand() + ", Data1: " + message.getData1() + ", Data2: " + message.getData2() + ", Tick: " + tick);
MidiEvent event = new MidiEvent(message, tick);
track.add(event);
}catch (Exception e){
e.printStackTrace();
}
}
public void saveMidiFile(){
try {
int[] fileTypes = MidiSystem.getMidiFileTypes(sequence);
if (fileTypes.length == 0) {
System.out.println("Can't save sequence");
} else {
if (MidiSystem.write(sequence, fileTypes[0], new File("testmidi.mid")) == -1) {
throw new IOException("Problems writing to file");
}
}
} catch (SecurityException ex) {
} catch (Exception ex) {
ex.printStackTrace();
}
}
void run(){
//System.out.println("sequence: " + sequence.getTracks().length);
createNewTrack(0);
createShortEvent(NOTEON, 60, 2);
createShortEvent(NOTEOFF, 60, 3);
createShortEvent(NOTEON, 61, 3);
createShortEvent(NOTEOFF, 61, 4);
createShortEvent(NOTEON, 62, 4);
createShortEvent(NOTEOFF, 62, 5);
createShortEvent(NOTEON, 63, 5);
createShortEvent(NOTEOFF, 63, 6);
createNewTrack(5);
createShortEvent(NOTEON, 50, 1);
createShortEvent(NOTEOFF, 50, 5);
playMidiFile();
saveMidiFile();
}
void printTrack(int num){
Track tempTrack = sequence.getTracks()[num];
System.out.println(tempTrack.get(0).getTick());
}
void playMidiFile(){
try{
sequencer.open();
sequencer.setSequence(sequence);
}catch (Exception e){
e.printStackTrace();
}
sequencer.start();
}
void createNewTrack(int program){
track = sequence.createTrack();
programChange(program);
}
void programChange(int program){
cc.channel.programChange(program);
System.out.println("program: " + program);
startTime = System.currentTimeMillis();
createShortEvent(PROGRAM, program);
}
public static void main(String[] args)
{
MidiTest2 mt = new MidiTest2();
mt.run();
}
}
ChannelData 类(什么都不做,但我想为了完整起见我会发布它):
public class ChannelData {
MidiChannel channel;
boolean solo, mono, mute, sustain;
int velocity, pressure, bend, reverb;
int row, col, num;
public ChannelData(MidiChannel channel, int num) {
this.channel = channel;
this.num = num;
velocity = pressure = bend = reverb = 64;
}
public void setComponentStates() {
}
}
在程序中,我尝试用原声钢琴声创建 5 个音符,用电钢琴声创建一个音符。但是,即使我在切换乐器之前创建了一个新音轨,所有音符都会以电钢琴的声音播放。
我现在已经尝试解决这个问题 5 个小时左右,但我完全没有想法。
【问题讨论】:
-
"为了完整起见,我想我会发布它" 如果它不相关,请不要发布它。同样,这仅发生在 5 个音符上,还是仅发生在 1 个音符上? stackoverflow.com/help/mcve我不是要固执,只是这里有很多代码要涉水。
-
是的,我明白你的意思。我的意思是让任何试图让代码运行的人更容易,在这种情况下,我认为如果它是完整的会更好。我得到了它的工作,结果证明我认为无关紧要的代码实际上做了。还是谢谢!