在发布此问题之前,我已经解决了问题。不过我认为这可能对其他人有所帮助,所以无论如何我都会发布它。如果有人知道更好或更优雅的方式来做这件事,请发一个答案。如果我同意,我当然会接受你的回答。这是我原来的问题:
我正在努力让以下内容与JSyn合作:
我想在两个声道上播放800Hz正弦波,并随时打开或关闭各个声道。所以,例如,我想要以下序列:
time 0s 0.3s 0.8s 1s 1s 1.1s 1.5s
left |--------------------| |-----------|
right |----| |------------------------|
我可以在一个或两个通道上生成正弦波,但我还没弄明白如何打开/关闭它们。这是一些代码:
import com.jsyn.JSyn;
import com.jsyn.Synthesizer;
import com.jsyn.unitgen.LineOut;
import com.jsyn.unitgen.SineOscillator;
public class MusicTest {
public static void main(String[] args) {
playSound();
}
public static void playSound() {
Synthesizer synth = JSyn.createSynthesizer();
try {
synth.start();
SineOscillator sineOsc1 = new SineOscillator(500, 0.2);
SineOscillator sineOsc2 = new SineOscillator(500, 0.2);
LineOut lineOut= new LineOut();
synth.add(lineOut);
synth.add(sineOsc1);
synth.add(sineOsc2);
sineOsc1.output.connect(0, lineOut.input, 0); // left channel
sineOsc2.output.connect(0, lineOut.input, 1); // right channel
lineOut.start();
sineOsc1.start(); // start left
sleep(1000);
sineOsc2.start(); // after 1s, start right
sleep(1000);
sineOsc1.stop(); // after 1s, stop left
sleep(1000);
sineOsc2.stop(); // after 1s, stop
lineOut.stop();
} finally {
synth.stop();
}
}
private static void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {}
}
}
不幸的是,这不起作用......
答案 0 :(得分:2)
第一个例子不起作用的原因是因为JSyn通过连接的单元生成器“拉”数据。
start()方法将单元添加到由引擎直接执行的单元列表中。你开始()链的末尾,例如LineOut。当一个单元执行时,它要求连接到其输入的任何单元的数据。反过来,这些单位要求连接到它们的任何单位的数据。这可以保证单元以最小化延迟的顺序执行。 JSyn检查循环连接以防止无限循环。
即使你停止()踩踏SineOscillators,LineOut仍然在拉它们。所以他们发出了声音。
不要在振荡器上调用start()或stop(),而是调用setEnabled(f)。这将阻止数据的提取。在第一个示例中尝试使用此代码段:
sineOsc1.setEnabled( false ); // begin disabled
sineOsc2.setEnabled( false );
lineOut.start();
sineOsc1.setEnabled(true); // start left
sleep(1000);
sineOsc2.setEnabled(true); // after 1s, start right
sleep(1000);
sineOsc1.setEnabled( false ); // after 1s, stop left
sleep(1000);
sineOsc2.setEnabled( false ); // after 1s, stop
另一种方法是使用一个振荡器并通过乘法单元将其连接到LineOut的每个通道。然后,您可以通过乘以1.0或0.0来打开或关闭该通道上的正弦值。这允许你乘以标量,例如。 0.5,如果你想成为一半。
sineOsc ---> multiply1 ---> lineOut(0) // left channel `--> multiply2 ---> lineOut(1) // right channel
我意识到setEnabled()和start()方法没有很好地记录。我现在就解决这个问题。
答案 1 :(得分:0)
解决方案是不要试图打开/关闭正弦波,而只是使用两个LineOut
。像这样:
public static void playSound() {
Synthesizer synth = JSyn.createSynthesizer();
try {
synth.start();
SineOscillator sineOsc1 = new SineOscillator(500, 0.2);
LineOut lineOut1 = new LineOut();
LineOut lineOut2 = new LineOut();
synth.add(lineOut1);
synth.add(lineOut2);
synth.add(sineOsc1);
sineOsc1.output.connect(0, lineOut1.input, 0); // connect to left channel
sineOsc1.output.connect(0, lineOut2.input, 1); // connect to right channel
lineOut1.start(); // start left
sleep(1000);
lineOut2.start(); // after 1s, start right
sleep(1000);
lineOut1.stop(); // after 1s, stop left
sleep(1000);
lineOut2.stop(); // after 1s, stop
} finally {
synth.stop();
}
}
我不知道这是否是最优雅的解决方案,但它的效果非常好。我希望这对其他人有帮助。