2013-12-10 3 views
0

Я новичок в программировании, и я пытаюсь сделать приложение Java, которое будет «слышать» (не обязательно записывать) звук и отображать, насколько громко. Я думаю о преобразовании звукозаписей в числа, поэтому я могу видеть разницу на уровнях звука. Я получил этот код, и я добавил метод getLevel(), который возвращает амплитуду текущей записи, но он возвращает -1 каждый раз. Я думаю, что я не используя его правильно. Любые идеи, как я должен назвать этот метод? Я должен доставить свой проект через неделю, поэтому любая помощь будет высоко оценена!Измеритель уровня звука

public class Capture extends JFrame { 

     protected boolean running; 
     ByteArrayOutputStream out; 

     public Capture() { 
     super("Capture Sound Demo"); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     Container content = getContentPane(); 

     final JButton capture = new JButton("Capture"); 
     final JButton stop = new JButton("Stop"); 
     final JButton play = new JButton("Play"); 

     capture.setEnabled(true); 
     stop.setEnabled(false); 
     play.setEnabled(false); 

     ActionListener captureListener = 
      new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
      capture.setEnabled(false); 
      stop.setEnabled(true); 
      play.setEnabled(false); 
      captureAudio(); 
      } 
     }; 
     capture.addActionListener(captureListener); 
     content.add(capture, BorderLayout.NORTH); 

     ActionListener stopListener = 
      new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
      capture.setEnabled(true); 
      stop.setEnabled(false); 
      play.setEnabled(true); 
      running = false; 
      } 
     }; 
     stop.addActionListener(stopListener); 
     content.add(stop, BorderLayout.CENTER); 

     ActionListener playListener = 
      new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
      playAudio(); 
      } 
     }; 
     play.addActionListener(playListener); 
     content.add(play, BorderLayout.SOUTH); 
     } 

     private void captureAudio() { 
     try { 
      final AudioFormat format = getFormat(); 
      DataLine.Info info = new DataLine.Info(
      TargetDataLine.class, format); 
      final TargetDataLine line = (TargetDataLine) 
      AudioSystem.getLine(info); 
      line.open(format); 
      line.start(); 

      Runnable runner = new Runnable() { 
      int bufferSize = (int)format.getSampleRate() 
       * format.getFrameSize(); 
      byte buffer[] = new byte[bufferSize]; 

      public void run() { 
       out = new ByteArrayOutputStream(); 
       running = true; 
       try { 
       while (running) { 
        int count = 
        line.read(buffer, 0, buffer.length); 
        if (count > 0) { 
        out.write(buffer, 0, count); 

        System.out.println(line.getLevel()); // |-this is what i added-| 
        } 
       } 
       out.close(); 
       } catch (IOException e) { 
       System.err.println("I/O problems: " + e); 
       System.exit(-1); 
       } 
      } 
      }; 
      Thread captureThread = new Thread(runner); 
      captureThread.start(); 
     } catch (LineUnavailableException e) { 
      System.err.println("Line unavailable: " + e); 
      System.exit(-2); 
     } 
     } 

     private void playAudio() { 
     try { 
      byte audio[] = out.toByteArray(); 
      InputStream input = 
      new ByteArrayInputStream(audio); 
      final AudioFormat format = getFormat(); 
      final AudioInputStream ais = 
      new AudioInputStream(input, format, 
      audio.length/format.getFrameSize()); 
      DataLine.Info info = new DataLine.Info(
      SourceDataLine.class, format); 
      final SourceDataLine line = (SourceDataLine) 
      AudioSystem.getLine(info); 
      line.open(format); 
      line.start(); 

      Runnable runner = new Runnable() { 
      int bufferSize = (int) format.getSampleRate() 
       * format.getFrameSize(); 
      byte buffer[] = new byte[bufferSize]; 

      public void run() { 
       try { 
       int count; 
       while ((count = ais.read(
        buffer, 0, buffer.length)) != -1) { 
        if (count > 0) { 
        line.write(buffer, 0, count); 
        } 
       } 

       line.drain(); 
       line.close(); 

       } catch (IOException e) { 
       System.err.println("I/O problems: " + e); 
       System.exit(-3); 
       } 
      } 
      }; 
      Thread playThread = new Thread(runner); 
      playThread.start(); 
     } catch (LineUnavailableException e) { 
      System.err.println("Line unavailable: " + e); 
      System.exit(-4); 
     } 
     } 

     private AudioFormat getFormat() { 
     float sampleRate = 8000; 
     int sampleSizeInBits = 8; 
     int channels = 1; 
     boolean signed = true; 
     boolean bigEndian = true; 
     return new AudioFormat(sampleRate, 
      sampleSizeInBits, channels, signed, bigEndian); 
     } 

     @SuppressWarnings("deprecation") 
    public static void main(String args[]) { 
     JFrame frame = new Capture(); 
     frame.pack(); 
     frame.show(); 
     } 
} 
+0

все, что вы сделали добавить 'System.out.println (line.getLevel()) ; '? См. Документацию: http://docs.oracle.com/javase/7/docs/api/javax/sound/sampled/DataLine.html#getLevel%28%29 "Возвращает: текущую амплитуду сигнала в этой строке , или AudioSystem.NOT_SPECIFIED «Таким образом, -1 означает, что что-то происходит неправильно. – turbo

+0

Обратите внимание, что 'running' доступен в разных потоках без синхронности: в потоке пользовательского интерфейса и в потоке захвата. Как правило, вы можете обеспечить получение текущего значения 'running', дефрагментируя его' volatile'. – Vertex

ответ

0

Да, как и @tubro, это AudioSystem.NOT_SPECIFIED = -1.

Я использую в своей программе следующую функцию, чтобы получить громкость в децибеле, вычислив средний квадрат корня. Обратите внимание, что я предполагаю нормализованные образцы со значениями от -1 до +1. Для этого я написал PCM Декодер которым поддерживают различные форматы 8, 16 бит, подписанный без знака, большой Endian и т.д.

public final class Loudness { 
    public static final float evaluate(final float[] window) { 
     if (window == null) { 
      throw new NullPointerException(); 
     } else if (window.length == 0) { 
      throw new IllegalArgumentException("window is empty"); 
     } 

     float sum = 0.0f; 
     for (int i = 0; i < window.length; i++) { 
      assert window[i] >= -1.0f && window[i] <= 1.0f; 
      sum += (window[i] * window[i]); 
     } 
     // Root Mean Square 
     // 0 <= rms <= 1 
     final float rms = (float) Math.sqrt(sum/window.length); 
     // 0 <= decibel 
     final float decibel = (float) (20 * Math.log10(rms)); 
     return decibel; 
    } 
} 
+0

Хорошо, мне удалось заставить захватить аудио и распечатать в файле xls временную метку и значение текущего образца, но есть проблема: даже я поместил пробелы между временем и значением, и кажется, что они находятся в разных столбцах, они действительны в одном столбце xls, он просто расширяется и охватывает следующий столбец (я могу поместить экран печати, если вы не понимаете). Как я могу заставить его печатать данные времени и амплитуда в двух разных столбцах? – xchris

+0

@xchris: Поместите табулятор между значением времени и измерения: 'System.out.println (time +" \ t "+ value)'. Скопируйте и вставьте консольный вывод в левую верхнюю ячейку в excel – Vertex

+0

Да, «\ t» не работал на csv, но он работает правильно на xls, спасибо! – xchris

Смежные вопросы