Несколько звуков на Java - PullRequest
4 голосов
/ 24 октября 2011

Я пытаюсь воспроизвести 2 звука (например, 220 Гц и 440 Гц) одновременно в Java.

Мне удалось воспроизвести один звук, используя StdAudio .Позже я сделал это не статичным и удалил некоторые методы, которые для меня не важны.

Чего я не знаю, так это как воспроизводить 2 звука одновременно.Я попытался сделать это с потоком, но они не всегда синхронизируются.

Ниже моя модифицированная версия StdAudio, и вот пример того, как я пытался использовать потоки.

программа.java

public class program {

    public static void main(String[] args) {
        Thread t1 = new Thread(new soundThread(220));
        t1.start();
        Thread t2 = new Thread(new soundThread(440));
        t2.start();

        t1.notify();
        t2.notify();
    }

}

soundThread.java

public class soundThread implements Runnable {
    private int fq;

    public soundThread(int fq) {
        this.fq = fq;
    }

    public void run() {
        StdAudio s = new StdAudio();
        double[] note = s.note(fq, 2, 1);
        try {
            this.wait();
        } catch (Exception e) {
        }

        s.play(note);

        s.close();
    }

}

StdAudio.java

/*************************************************************************
 *  Compilation:  javac this.java
 *  Execution:    java StdAudio
 *  
 *  Simple library for reading, writing, and manipulating .wav files.

 *
 *  Limitations
 *  -----------
 *    - Does not seem to work properly when reading .wav files from a .jar file.
 *    - Assumes the audio is monaural, with sampling rate of 44,100.
 *
 *************************************************************************/

import javax.sound.sampled.*;

/**
 * <i>Standard audio</i>. This class provides a basic capability for creating,
 * reading, and saving audio.
 * <p>
 * The audio format uses a sampling rate of 44,100 (CD quality audio), 16-bit,
 * monaural.
 * 
 * <p>
 * For additional documentation, see <a
 * href="http://introcs.cs.princeton.edu/15inout">Section 1.5</a> of
 * <i>Introduction to Programming in Java: An Interdisciplinary Approach</i> by
 * Robert Sedgewick and Kevin Wayne.
 */
public final class StdAudio {

    /**
     * The sample rate - 44,100 Hz for CD quality audio.
     */
    public final int SAMPLE_RATE = 44100;

    private final int BYTES_PER_SAMPLE = 2; // 16-bit audio
    private final int BITS_PER_SAMPLE = 16; // 16-bit audio
    private final double MAX_16_BIT = Short.MAX_VALUE; // 32,767
    private final int SAMPLE_BUFFER_SIZE = 4096;

    private SourceDataLine line; // to play the sound
    private byte[] buffer; // our internal buffer
    private int bufferSize = 0; // number of samples currently in internal
                                // buffer

    // initializer
    {
        init();
    }

    // open up an audio stream
    private void init() {
        try {
            // 44,100 samples per second, 16-bit audio, mono, signed PCM, little
            // Endian
            AudioFormat format = new AudioFormat((float) SAMPLE_RATE,
                    BITS_PER_SAMPLE, 1, true, false);
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

            line = (SourceDataLine) AudioSystem.getLine(info);
            line.open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE);

            // the internal buffer is a fraction of the actual buffer size, this
            // choice is arbitrary
            // it gets divided because we can't expect the buffered data to line
            // up exactly with when
            // the sound card decides to push out its samples.
            buffer = new byte[SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE / 3];
        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.exit(1);
        }

        // no sound gets made before this call
        line.start();
    }

    /**
     * Close standard audio.
     */
    public void close() {
        line.drain();
        line.stop();
    }

    /**
     * Write one sample (between -1.0 and +1.0) to standard audio. If the sample
     * is outside the range, it will be clipped.
     */
    public void play(double in) {

        // clip if outside [-1, +1]
        if (in < -1.0)
            in = -1.0;
        if (in > +1.0)
            in = +1.0;

        // convert to bytes
        short s = (short) (MAX_16_BIT * in);
        buffer[bufferSize++] = (byte) s;
        buffer[bufferSize++] = (byte) (s >> 8); // little Endian

        // send to sound card if buffer is full
        if (bufferSize >= buffer.length) {
            line.write(buffer, 0, buffer.length);
            bufferSize = 0;
        }
    }

    /**
     * Write an array of samples (between -1.0 and +1.0) to standard audio. If a
     * sample is outside the range, it will be clipped.
     */
    public void play(double[] input) {
        for (int i = 0; i < input.length; i++) {
            play(input[i]);
        }
    }

    /**
     * Create a note (sine wave) of the given frequency (Hz), for the given
     * duration (seconds) scaled to the given volume (amplitude).
     */
    public double[] note(double hz, double duration, double amplitude) {
        int N = (int) (this.SAMPLE_RATE * duration);
        double[] a = new double[N + 1];
        for (int i = 0; i <= N; i++)
            a[i] = amplitude
                    * Math.sin(2 * Math.PI * i * hz / this.SAMPLE_RATE);
        return a;
    }

}

Заранее спасибо, Шэй Бен Моше

РЕДАКТИРОВАТЬ: Решение было написать этот метод:

public double[] multipleNotes(double[] hzs, double duration,
        double amplitude) {
    amplitude = amplitude / hzs.length;
    int N = (int) (SAMPLE_RATE * duration);
    double[] a = new double[N + 1];
    for (int i = 0; i <= N; i++) {
        a[i] = 0;
        for (int j = 0; j < hzs.length; j++)
            a[i] += amplitude
                    * Math.sin(2 * Math.PI * i * hzs[j] / SAMPLE_RATE);
    }
    return a;
}

EDIT2: Еще лучшее решение для меня (O (1) памяти):

public void multiplePlay(double[] hzs, double duration, double amplitude) {
    amplitude = amplitude / hzs.length;
    int N = (int) (SAMPLE_RATE * duration);
    double sum;
    for (int i = 0; i <= N; i++) {
        sum = 0;
        for (int j = 0; j < hzs.length; j++)
            sum += amplitude
                    * Math.sin(2 * Math.PI * i * hzs[j] / SAMPLE_RATE);
        this.play(sum);
    }
}

Ответы [ 4 ]

6 голосов
/ 24 октября 2011

Немного расширяю свой комментарий о простом объединении двух звуков в один ...

Вы показали это:

public double[] note(double hz, double duration, double amplitude) {
    int N = (int) (this.SAMPLE_RATE * duration);
    double[] a = new double[N + 1];
    for (int i = 0; i <= N; i++)
        a[i] = amplitude
                * Math.sin(2 * Math.PI * i * hz / this.SAMPLE_RATE);
    return a;
}

Так как насчет того, чтобы смешать два звука в один и воспроизвести этот уникальный звук? Например, вы можете сделать что-то вроде этого:

public double[] notes(double hz1, double hz2, double duration, double amplitude) {
    final double[] a1 = note( hz1, duration, amplitude );
    final double[] a2 = note( hz2, duration, amplitude );
    final double[] a3 = new double[a2.length];
    for ( int i = 0; i < a1.length; i++ ) {
        a3[i] = (a1[i] + a2[i]) / 2;       
    }
    return a3;
}

И вы бы просто назвали это так:

final double[] sound = notes(220,400,...,...);
0 голосов
/ 17 июня 2013

Вы можете воспроизводить несколько звуков определенной частоты, используя библиотеку JSyn.

Это будет работать для того, что вы хотите прямо сейчас, и вы можете перейти к нему позже, если вы хотите сделать что-нибудь более сложное.

http://www.softsynth.com/jsyn/

В качестве примера мне также удалось выяснить некоторые более сложные звуки:

JSyn, звук сирены с использованием генератора, который подается / контролируется / inputInto / daisy-chainedTo другим генератором и константой ... и генерирует более одного звука

Этот код выполняет генерацию тонов при 220 Гц и 440 Гц одновременно.

com.jsyn.Synthesizer synth = JSyn.createSynthesizer ();
com.jsyn.unitgen.SineOscillator sine1 = новый SineOscillator ();
com.jsyn.unitgen.SineOscillator sine2 = новый SineOscillator ();
com.jsyn.unitgen.LineOut lineOut = new LineOut ();

* * Synth.add тысячу двадцать-один (sine1); * +1022 * synth.add (Sine2); * +1023 * synth.add (LineOut);
* +1025 * sine1.frequency.set (220);

sine2.frequency.set (440); * 1 027 *

sine1.output.connect (0, lineOut.input, 0); // левый и правый каналы
sine1.output.connect (0, lineOut.input, 1);
sine2.output.connect (0, lineOut.input, 0); // левый и правый каналы
sine2.output.connect (0, lineOut.input, 1);

lineOut.start (); * * тысяча тридцать четыре

0 голосов
/ 24 октября 2011

API-интерфейс OpenAL с открытым исходным кодом, доступный в iOS в платформе OpenAL, обеспечивает интерфейс, оптимизированный для позиционирования звуков в стереофоническом поле во время воспроизведения. Воспроизведение, позиционирование и перемещение звуков работает так же, как и на других платформах. OpenAL также позволяет смешивать звуки. Здесь для больше: http://developer.apple.com/library/IOS/#documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html

0 голосов
/ 24 октября 2011

Попробуйте Pulpcore

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...