JSyn: синусоида на двух каналах

Я разобрался с проблемой, прежде чем опубликовать этот вопрос. Тем не менее, я думаю, что это может помочь кому-то еще, поэтому я все равно публикую это. Если кто-нибудь знает лучший или более элегантный способ сделать это, пожалуйста, оставьте ответ. Если я согласен, я, конечно, приму ваш ответ. Вот моя оригинальная проблема:

Я пытаюсь заставить работать с JSyn следующее:

Я хочу воспроизвести синусоидальный сигнал 800 Гц на двух каналах и включать или выключать отдельные каналы в любое время. Так, например, я хочу следующую последовательность:

 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) {}
    }
}

К сожалению, это не работает...

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) // левый канал
            `-> multiply2 ---> lineOut(1) // правый канал

Я понимаю, что методы setEnabled() и start() плохо документированы. Я исправлю это сейчас.

Решение состоит в том, чтобы не пытаться включить / выключить синусоидальную волну, а просто использовать два 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();
    }
}

Я не знаю, является ли это самым элегантным решением, но оно действительно отлично работает. Я надеюсь, что это поможет кому-то еще.

Другие вопросы по тегам