我正在编写一个具有两个振荡器的合成器应用程序,每个振荡器都在自己的线程中运行。我想要做的是混合来自这两个振荡器的信号。当振荡器填充缓冲区时,它会通过调用其同步方法SynthMixer
将其传递给sendBuffer()
对象。
package mixer_test;
public class SynthMixer {
Synth synth;
double[] buffer1, buffer2;
boolean buffersProcessed;
public SynthMixer(Synth synth){
buffer1 = null;
buffer2 = null;
this.synth = synth;
}
public synchronized void sendBuffer(double[] buffer) {
if (buffer1 == null) {
buffersProcessed = false;
buffer1 = new double[Synth.bufferSize];
for (int i = 0; i < Synth.bufferSize; i++) {
buffer1[i] = buffer[i];
}
try {
while(!buffersProcessed) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
buffer2 = buffer;
mixAndPass();
buffer1 = null;
buffer2 = null;
buffersProcessed = true;
notify();
}
}
private void mixAndPass(){
double[] outBuffer = new double[Synth.bufferSize];
for(int i = 0; i < Synth.bufferSize; i++){
outBuffer[i] = (buffer1[i] + buffer2[i])/2;
}
synth.passBuffer(outBuffer);
}
}
package mixer_test;
public class Oscillator {
WaveShape wave;
boolean hold;
SynthMixer mixer;
public Oscillator(WaveShape wave, SynthMixer mixer){
this.wave = wave;
this.mixer = mixer;
hold = true;
}
public void start(int frequency){
wave.setFrequency(frequency);
Thread oscillatorLoop = new Thread(new Runnable(){
public void run(){
int sampleNo = 0;
double[] buffer = new double[Synth.bufferSize];
while(hold){
for(int i = 0; i < Synth.bufferSize; i++){
buffer[i] = wave.getSample(sampleNo + i);
}
mixer.sendBuffer(buffer);
sampleNo += Synth.bufferSize;
}
}
});
oscillatorLoop.start();
}
public void stop(){
hold = false;
}
}
package mixer_test;
public class Synth {
public static final int sampleRate = 44100;
public static final int bitDepth = 16;
public static final int bufferSize = 512;
Oscillator osc1, osc2;
SynthMixer mixer;
Amp amp1; // converts double[] to byte[] and writes to SourceDataLine instance
public Synth(){
mixer = new SynthMixer(this);
osc1 = new Oscillator(WaveShape.SINE, mixer );
osc2 = new Oscillator(WaveShape.SINE, mixer);
amp1 = new Amp();
}
public void passBuffer (double[] buffer){
amp1.sendBuffer(buffer);
}
public void play(){
osc2.start(400);
osc1.start(420);
}
public static void main (String[] args){
Synth synth = new Synth();
synth.play();
}
}
编写此代码时我的想法如下:
其中一个振荡器让我们说在线程A上运行的Osc A完成填充缓冲区并调用sendBuffer()
。线程A保持SynthMixer
对象锁定,因此即使线程B上的振荡器完成渲染缓冲区,它也会在调用sendBuffer()
之前等待,直到锁被释放。因此,线程A调用sendBuffer()
,buffer1字段为null,因此if语句执行将传递的缓冲区写入此字段。然后线程A等待释放锁,因此线程B可以调用该方法。现在buffer1不再为null,所以我们将振荡器B传递的缓冲区写入buffer2字段。 mixAndPass()
接受两个缓冲区并将其混合。在此之后notify()
唤醒线程A并且该进程重复下一个缓冲区。
但效果是只有通过的信号才是最后启动线程的振荡器的信号。在调试代码时,我可以看到,当调用wait()
时,buffer1的值突然变为null。我无法理解为什么会这样,并且非常感谢有关如何使其正常工作的解释和建议。