Главная > Soft > Детектирование звука на Java

Детектирование звука на Java

После небольших экспериментов с детектором движения на java пришла пора детектировать звук. Для этой задачи можно воспользоваться Java SDK, пакет «javax.sound.sampled». Работа будет основана на примере записи звука в javа. Для этого придётся разобраться, какая информация приходит в AudioInputStream.

Sound detector

В примере использовались следующие настройки для формата входного сигнала:

AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100.0F, 16, 2, 4, 44100.0F, false);

Это означает, что входной сигнал будет с частотой дискретизации в 44.1кГц, 2 канала, значения от  -2^15 до 2^15 на канал и кодироваться будет знаковым числом с младшим байтом в начале.

digital signal

Идея состоит в том, чтоб постоянно получать значение одного из каналов и сравнивать его с некоторым заранее заданным числом, которое задаёт чувствительность (15000 в примере). Если значение превысит число, то начинается автоматическая запись длинною в 10 секунд.

package info.privateblog;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;

public class TestSound2 extends Thread    {
	private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH_mm_ss");

	private TargetDataLine  m_line;
    private AudioInputStream m_audioInputStream;
    private File m_outputFile;

    public TestSound2(TargetDataLine m_line, File m_outputFile) {
        this.m_line = m_line;
        this.m_audioInputStream = new AudioInputStream(m_line);
        this.m_outputFile = m_outputFile;
    }

    public void start() {
        m_line.start();
        super.start();
    }

    public void stopRecording() {
        m_line.stop();
    }

    public void run() {
    	try {
    		AudioSystem.write(m_audioInputStream, AudioFileFormat.Type.WAVE, m_outputFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static void main(String args[]) throws IOException, LineUnavailableException, InterruptedException {
        AudioFormat    audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100.0F, 16, 2, 4, 44100.0F, false);

        DataLine.Info    info = new DataLine.Info(TargetDataLine.class, audioFormat);
        TargetDataLine    targetDataLine = (TargetDataLine) AudioSystem.getLine(info);

        targetDataLine.open(audioFormat);
        
    	AudioInputStream audioInputStream = new AudioInputStream(targetDataLine);  
    	byte[]buffer = new byte[4];
    	
    	targetDataLine.start();
    	
    	while(audioInputStream.read(buffer) > 0) {
			int value = ((buffer[0] & 0xff) | (buffer[1] << 8)) << 16 >> 16;
	        //System.out.println("Value: " + value);

			if (value > 15000) {//32768
		        System.out.println("Found " + value);

				targetDataLine.stop();

				startRecording(targetDataLine);
				
	        	targetDataLine.start();
	        	
		        System.out.println("Looking");
			}
    	}

		targetDataLine.stop();
        targetDataLine.close();

        System.out.println("Recording stopped.");
   }
    
   private static void  startRecording(TargetDataLine targetDataLine) throws InterruptedException {
      String fileName = "e:/new/recording_" + sdf.format(new Date()) + ".wav";
	   
       File outputFile = new File(fileName);	
	   
       TestSound2 j = new TestSound2(targetDataLine, outputFile);
       j.start();
       Thread.currentThread().sleep(10000);
       j.stopRecording();
   }
}
Categories: Soft Tags: ,
  1. QSucka
    17 Апрель 2016 в 20:58 | #1

    Нигде не могу найти русские туториалы по Java Sound API. Или английские но для начинающих. Может поделитесь ссылкой?
    И еще не подскажите как остановить запись после скажем после 2 сек молчания.




    0



    0
  2. QSucka
    18 Апрель 2016 в 21:40 | #3

    @Admin
    Жаль(( И на этом спасибо.
    А что по поводу остановки записи после 2 сек молчания? Нужно в отдельном потоке как то организовывать проверку сигнала микрофона?




    0



    0
  3. Mirgorod
    23 Ноябрь 2017 в 05:14 | #4

    ув. автор, стараюсь разобраться с Java Sound API.
    Ваш пример с определением уровня громкости почти идеально подходит под мою проблему.
    Весь фокус ведь в этой строчке?:
    int value = ((buffer[0] & 0xff) | (buffer[1] << 8)) <> 16;
    Влияет ли формат входного сигнала на неё?




    0



    0
    • Admin
      23 Ноябрь 2017 в 11:42 | #5

      Насколько я помню, у меня входной сигнал — 16 бит на один канал. Поэтому и пытаюсь получить модуль амплитуды и сравнить с каким-нибудь значением. На практике такое сравнение работает неплохо.
      Но надо разбираться, какая шкала используется для громкости. Может, она не линейная, а логарифмическая.




      0



      0
  4. Mirgorod
    23 Ноябрь 2017 в 15:57 | #6

    Ну допустим. Разбираться, оно, конечноно же, нужно, но мне к этому нужно еще добраться.
    int value = ((buffer[0] & 0xff) | (buffer[1] << 8)) <> 16; вот эта строчка. Можете сказать что это вообще такое, как называется, и что про неё прочитать, а то я такое вижу впервые и хотелось бы хотя бы немного понять что это.




    0



    0
    • Admin
      23 Ноябрь 2017 в 17:26 | #7

      Что-то типа такого, только в битовых операциях.
      Math.abs(buffer[1]*256 + buffer[0]);

      PS: поищите на тему «little-endian»




      0



      0
  1. Пока что нет уведомлений.