我正在编写一个小鼓音序器,一个roland tr808仿冒品,16步/测量和16个乐器(=鼓样本)。用户可以创建一个16x16模式。
然而,如果一个样本连续播放不止一次,它通常只播放一次。比如说,我在第1,5,9和13步以及节奏130BPM上得到了一个bassdrum,它有时只在1和9上播放bd,有时也在5和/或13上播放。如果样本非常短或速度很慢,则模式中的每一步都可以正确播放的可能性更高。因此,当我尝试再次播放样本时,我认为音频线并不喜欢它。
但实际上我认为我已经在我的代码中考虑到了这一点。如果有人告诉我我的代码有什么问题,我真的很感激。
这是我安德鲁汤普森建议的完整代码,修改后需要从互联网上获取一些样本。但是加载它们需要一点时间。导致问题的部分可能是Instrument类中的play()方法:
package testbox;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.sound.sampled.*;
public class boomboxtest {
public static void main(String[] args) {
Sequencer seq = new Sequencer();
//bassdrum
seq.toggleInstrument(0,0);
seq.toggleInstrument(0,4);
seq.toggleInstrument(0,8);
seq.toggleInstrument(0,12);
//snare
seq.toggleInstrument(1,4);
seq.toggleInstrument(1,12);
//Hihat
seq.toggleInstrument(2, 2);
seq.toggleInstrument(2, 6);
seq.toggleInstrument(2, 10);
//Bongo
seq.toggleInstrument(3, 6);
seq.toggleInstrument(3, 10);
seq.setTempo(130);
seq.play();
}
}
class Sequencer {
private Mixer mixer;
private List<SequencerListener> listeners = new ArrayList<SequencerListener>();
public static final int INSTR_COUNT = 4;
private int tempo_bpm = 120;
private ExecutorService executor;
private int current_step = 0;
private int current_max_step = 16;
private boolean[][] pattern = new boolean[32][INSTR_COUNT];
private ArrayList<Instrument> instruments;
Line[] lines = new Line[16];
private SequencerEngine seq;
private String[] filenames = {"http://www.canadianmusicartists.com/sample/kick_02.wav", "http://www.canadianmusicartists.com/sample/snare01.wav", "http://www.canadianmusicartists.com/sample/H_closedhat_01.wav", "http://www.canadianmusicartists.com/sample/bongo01.wav"};
public Sequencer() {
seq = new SequencerEngine();
try{
Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
mixer = AudioSystem.getMixer(mixerInfo[0]);
} catch (Exception e) {e.printStackTrace();}
instruments = new ArrayList<Instrument>(INSTR_COUNT);
for (int i = 0; i < INSTR_COUNT; i++) {
System.out.println("Loading instrument " + i);
Instrument instr = new Instrument(filenames[i], mixer);
instruments.add(instr);
lines[i] = instr.getLine();
}
syncMixer();
executor = Executors.newCachedThreadPool();
executor.submit(seq);
}
public void syncMixer() {
if (mixer.isSynchronizationSupported(lines, false)) {
mixer.synchronize(lines, false);
} else {
System.out.println("No hay synchronisado");
}
}
public boolean isPlaying() {
return seq.getRunning();
}
public boolean toggleInstrument (int instrument, int beat) {
pattern[beat][instrument] = !pattern[beat][instrument];
return pattern[beat][instrument];
}
public void play() {
seq.toggleRun(true);
}
public void pause() {
seq.toggleRun(false);
}
public void stop() {
pause();
setCurrent_step(0);
}
public int getTempo() {
return tempo_bpm;
}
public void setTempo(int tempo) {
if (tempo < 30) {
tempo = 30;
} else if (tempo > 200) {
tempo = 200;
} else {
this.tempo_bpm = tempo;
}
}
public int getCurrent_step() {
return current_step;
}
public void setCurrent_step(int current_step) {
this.current_step = current_step;
}
public boolean[][] getPattern() {
return pattern;
}
public void kill() {
seq.kill();
executor.shutdownNow();
}
public void addListener(SequencerListener toAdd) {
listeners.add(toAdd);
}
public class SequencerEngine implements Runnable{
private boolean running;
private boolean alive = true;
public void run() {
while( getAlive()) {
while (getRunning()) {
if (current_step >= current_max_step) {
current_step = 0;
}
for (; current_step < current_max_step ; current_step++) {
stepListen();
if(!getRunning()) {
break;
}
long time = System.currentTimeMillis();
long steptime = 60000/(4*tempo_bpm);
for (int k = 0; k < INSTR_COUNT; k++) {
if (pattern[current_step][k]) {
instruments.get(k).play();
}
}
while((System.currentTimeMillis()-time) < steptime) {}
}
}
}
}
public void stepListen() {
for (SequencerListener sl : listeners) {
sl.stepEvent(current_step);
}
}
public boolean getRunning() {
return running;
}
public boolean getAlive() {
return alive;
}
public void toggleRun(boolean toggle) {
running = toggle;
}
public void kill() {
alive = false;
}
}
}
class Instrument {
private String name;
private File soundFile;
private AudioInputStream stream;
private AudioFormat format;
private DataLine.Info info;
private Clip clip;
private Mixer mixer;
public Instrument(String filename, Mixer mixer ) {
this.name = filename;
try {
//soundFile = new File("sounds/" + filename);
URL url = new URL(filename);
this.mixer = mixer;
//stream = AudioSystem.getAudioInputStream(soundFile);
stream = AudioSystem.getAudioInputStream(url);
format = stream.getFormat();
info = new DataLine.Info(Clip.class, format);
clip = (Clip) mixer.getLine(info);
clip.open(stream);
}
catch (Exception e) {
e.printStackTrace();
}
}
public void play() {
clip.stop();
clip.setFramePosition(0);
clip.start();
}
public Line getLine() {
return clip;
}
}
interface SequencerListener {
void stepEvent(int current_step);
}
样品质量相当可疑,但特别是bassdrum样品说明我的问题非常好。