Звуковой сигнал Java: Произведите звук некоторых конкретных частот

Я экспериментировал с созданием звукового сигнала с использованием Java. Я нашел этот ответ на SO.

Я использую код из этого ответа для создания звуковых сигналов. Код:

import javax.sound.sampled.*;
public class Sound
{
    public static float SAMPLE_RATE = 8000f;
    public static void tone(int hz, int msecs) 
    throws LineUnavailableException 
    {
        tone(hz, msecs, 1.0);
    }

    public static void tone(int hz, int msecs, double vol)
    throws LineUnavailableException 
    {
        byte[] buf = new byte[1];
        AudioFormat af = new AudioFormat(SAMPLE_RATE,8,1,true,false);     
        SourceDataLine sdl = AudioSystem.getSourceDataLine(af);
        sdl.open(af);
        sdl.start();
        for (int i=0; i < msecs*8; i++) {
              double angle = i / (SAMPLE_RATE / hz) * 2.0 * Math.PI;
              buf[0] = (byte)(Math.sin(angle) * 127.0 * vol);
              sdl.write(buf,0,1);
        }
        sdl.drain();
        sdl.stop();
        sdl.close();
    }

    public static void main(String[] args) throws Exception {
        Sound.tone(15000,1000); 
    }
}

В методе main я использую Sound.tone(15000,1000); для создания звука с частотой 15000 Гц для воспроизведения 1000 мс

Но я могу услышать звук, если я изменю его на:

  • Sound.tone(1,1000);,.
  • Sound.tone(19999,1000);

С научной точки зрения, это невозможно.

  • В первом случае звук должен быть infrasonic, и я не должен его воспринимать.
  • Во втором случае мне все равно не удастся услышать звук, потому что, поскольку мы стареем, способность слышать имеет тенденцию к уменьшению, и человек примерно моего возраста должен только слышать звук приблизительно 16000 Гц.

Кроме того, я не слышу:

  • Sound.tone(0,1000); (как бы ожидалось)
  • Sound.tone(20000,1000);

Итак, Как я могу воспроизводить звуки некоторых определенных частот?
Я искал в Интернете, но ничего не мог найти по этому поводу.

Ответы, приведенные перед этим редактированием, объясняют, почему это происходит, но не давайте ответа, который я хочу.

Ответ 1

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

Звуковая выборка имеет тот же артефакт и называется теоремой выборки Найквиста, которая в основном указывает, что вы можете представлять только частоты до половины частоты дискретизации (частота nyquist). Выходя за эту частоту, тона начинают отбрасываться (например, поворачивать назад).

При частоте дискретизации 8 кГц частоты от 0 Гц до 4 кГц будут воспроизводиться отлично (синусоидальная частота 4 кГц будет иметь 2 отсчета за период). Вне 4 кГц частоты начнут складываться назад, так что 4001 Гц будет слышен как 3999, 5000 Гц как 3000 Гц и, в конечном счете, 8000 Гц как 0 Гц (отсюда и молчание). Помимо 8 кГц он снова начнет складываться так, чтобы 8001 Гц составлял 1 Гц и т.д.

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

Ответ 2

Просто перепроверяется с гитарным тюнером перед моим динамиком - метод, который вы предоставили, является точным для низких частот.

Однако, если вы получите слишком низкий, вы можете услышать обертоны или "заикание" звука из-за того, что динамики не работают слишком сильно при инфразвуке (по крайней мере, я понял)

В высоких частотах ваш код не слишком хорошо вычисляется - с частотой выборки 8000 выборок в секунду вы быстро создадите "недопустимые" тона для более высоких частот - колебание синусоидальной волны будет просто случайно совпадают с частотой дискретизации. Таким образом, вы получите некоторые высокие частоты, которые вы можете услышать (в основном потому, что ваши образцы всегда попадают в какое-то ненулевое значение) или не слышат (все ваши образцы возникают в моменты, когда волна проходит через нуль.

Проверьте этот цикл (с включенным динамиком):

 public static void main(String[] args) throws Exception {
    for(int freq = 400; freq < 20000; freq *= 2) {
        Sound.tone(freq,500);
    }
 }

В конце вы услышите низко-высокий-низкий-высокий по причинам, описанным ниже.

Еще одно испытание:

  Sound.tone(8000,500);   

абсолютно бесшумен, и

  Sound.tone(8001,500);

производит очень фанковый звук.