2015-08-08 4 views
1

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

Код выглядит следующим образом:

package com.funguscow; 

import javax.sound.sampled.AudioFormat; 
import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.DataLine; 
import javax.sound.sampled.SourceDataLine; 
import javax.sound.sampled.TargetDataLine; 

public class Listen { 

    public static void main(String[] args){ 
     AudioFormat format = new AudioFormat(44100, 16, 2, true, true); //get the format for audio 

     DataLine.Info targetInfo = new DataLine.Info(TargetDataLine.class, format); //input line 
     DataLine.Info sourceInfo = new DataLine.Info(SourceDataLine.class, format); //output line 

     try { 
      TargetDataLine targetLine = (TargetDataLine) AudioSystem.getLine(targetInfo); 
      targetLine.open(format); 
      targetLine.start(); 

      SourceDataLine sourceLine = (SourceDataLine) AudioSystem.getLine(sourceInfo); 
      sourceLine.open(format); 
      sourceLine.start(); 

      int numBytesRead; 
      byte[] targetData = new byte[sourceLine.getBufferSize()]; 

      while (true) { 
       numBytesRead = targetLine.read(targetData, 0, targetData.length); //read into the buffer 

       if (numBytesRead == -1) break; 

       for(int i=0; i<numBytesRead/2; i++){ //apply hard distortion/clipping 
        int j = (((targetData[i * 2]) << 8) & 0xff00) | ((targetData[i * 2 + 1]) & 0xff); 
        j *= 2; 
        if(j > 65535) j = 65535; 
        if(j < 0) j = -0; 
        targetData[i * 2] = (byte)((j & 0xff00) >> 8); 
        targetData[i * 2 + 1] = (byte)(j & 0x00ff); 
       } 

       sourceLine.write(targetData, 0, numBytesRead); //play 
      } 
     } 
     catch (Exception e) { 
      System.err.println(e); 
     } 
    } 

} 

Как есть задержка, что, как представляется, примерно 1 вторых, можно ли это исправить?

+0

У меня такая же проблема. Если кто-то нашел ответ, напишите здесь. –

+0

Я не нашел окончательной информации об этом, но изменение размера буфера на .open() определенно является правильным подходом. Однако, по моему опыту, вам не нужно и не очень хочется сделать его таким же маленьким, как то, что вы хотите попробовать. Например, 4196 позвольте мне взять образцы в 2048 блоках. 44100 меня не пускает. Чтобы понять это, я помещаю временные выражения вокруг read(). Если вы видите, что прочитанные практически 0 миллисов, что-то не так. – Joel

ответ

0

Каков максимальный буфер, который был возвращен с sourceLine.getBufferSize()? Если вы читаете с микрофона с частотой 44 100 выборок в секунду при 2 байтах/образце, для заполнения буфера с байтами в 88 200 байт требуется ровно 1 секунда. Я бы предположил, что системный буфер находится вокруг этого размера. Попробуйте использовать меньший буфер в строке byte[] targetData = new byte[sourceLine.getBufferSize()]; Я бы рекомендовал держать его достаточно маленьким, чтобы латентность звука составляла 10 миллисекунд или меньше (так что 882 байта или меньше) для лучшего удобства пользователя.

0

Я объявляю окончательный int с размером буфера. Задержка в 10 миллисекунд будет представлять собой количество байтов на кадр, умноженное на количество кадров в секунду, деленное на 100. Если стерео 16-битное кодирование (качество CD) со скоростью 44100 кадров в секунду, это будет (4 * 44100)/100 = 1764 байт ,

Затем откройте оба TargetDataLine и SourceDataLine с этим размером буфера:

targetLine.open(format, BUFFER_SIZE); 
sourceLine.open(format, BUFFER_SIZE); 

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

Вы также должны использовать константу в чтениях и записи.

Возможно, вам придется играть со значением, чтобы оно было оптимальным. Следовательно, имеет смысл определить его только один раз, поэтому вам не нужно делать несколько изменений. Значение должно соответствовать количеству байтов, необходимых для целого числа кадров, которые должны быть прочитаны или записаны. Слишком высокая латентность увеличения, слишком низкая увеличивает вероятность отсева.

10 миллисов будет очень хорошим, особенно если вы не имеете дело с чрезмерно ударными звуками.