前提・実現したいこと
外部の音声を波形として表示するプログラムを作成しています。一応、30fpsを仮定し、30ミリ秒ごとに波形を表示するものとしています。
該当のソースコード
Spectrum.java
Java
1import java.awt.BasicStroke; 2import java.awt.Graphics; 3import java.awt.Graphics2D; 4import java.awt.geom.Line2D; 5import java.io.IOException; 6 7import javax.sound.sampled.AudioFormat; 8import javax.sound.sampled.AudioInputStream; 9import javax.sound.sampled.AudioSystem; 10import javax.sound.sampled.LineUnavailableException; 11import javax.sound.sampled.TargetDataLine; 12import javax.swing.JPanel; 13 14public class Recorder extends JPanel implements Runnable { 15 16 private AudioFormat fmt; 17 private byte data[]; 18 private byte dataCopy[]; 19 private TargetDataLine line; 20 21 private static final int SAMPLE_RATE = 44100; 22 private static final int SAMPLE_BITS = 8; 23 private static final int CHANNELS = 1; 24 private static final boolean IS_SIGNED = true; 25 private static final boolean IS_BIG_ENDIEN = true; 26 private static final double READ_LENGTH = 0.03; // 30fps 27 28 private int loop; 29 private static final boolean DEBUG = true; 30 31 public Recorder() { 32 fmt = new AudioFormat(SAMPLE_RATE, SAMPLE_BITS, CHANNELS, IS_SIGNED, IS_BIG_ENDIEN); 33 data = new byte[(int) (SAMPLE_RATE * READ_LENGTH)]; 34 dataCopy = data.clone(); 35 36 try { 37 line = AudioSystem.getTargetDataLine(fmt); 38 line.open(); 39 } catch (LineUnavailableException e) { 40 e.printStackTrace(); 41 } 42 } 43 44 public void doRecord() { 45 // 別スレッドに分ける 46 Thread thread = new Thread(this); 47 thread.start(); 48 } 49 50 public void run() { 51 AudioInputStream in = new AudioInputStream(line); 52 line.start(); 53 try { 54 if (DEBUG) { 55 for (loop = 1; loop <= 100; loop++) { 56 long c0 = System.nanoTime(); 57 in.read(data, 0, data.length); 58 long c1 = System.nanoTime(); 59 dataCopy = data.clone(); // 読み取りと書き取りの衝突防止 60 long c2 = System.nanoTime(); 61 repaint(); 62 long c3 = System.nanoTime(); 63 System.out 64 .println("[Main Loop] Loop " + loop + ": " + 65 (c1 - c0)/1000000.0 + " " + (c2 - c1)/1000000.0 + " " + (c3 - c2)/1000000.0); 66 } 67 } else { 68 while (true) { 69 in.read(data, 0, data.length); 70 dataCopy = data.clone(); // 読み取りと書き取りの衝突防止 71 repaint(); 72 } 73 } 74 } catch (IOException e) { 75 e.printStackTrace(); 76 } 77 line.stop(); 78 line.close(); 79 } 80 81 @Override 82 public void paintComponent(Graphics g) { 83 long c0 = System.nanoTime(); 84 super.paintComponent(g); 85 Graphics2D g2 = (Graphics2D) g; 86 BasicStroke wideStroke = new BasicStroke(4.0f); 87 g2.setStroke(wideStroke); 88 for (int i = 0; i < data.length - 1; i++) { 89 Line2D line = new Line2D.Double( 90 toXCoodinate(i, 1000), toYCoodinate(dataCopy[i], 600), 91 toXCoodinate(i + 1, 1000), toYCoodinate(dataCopy[i + 1], 600)); 92 g2.draw(line); 93 } 94 long c1 = System.nanoTime(); 95 if (DEBUG) { 96 System.out.println("[Repeint] Loop " + loop + ": " + (c1 - c0)/1000000.0); 97 } 98 } 99 100 private int toXCoodinate(int pos, int width) { 101 double w = (double) width; 102 return (int) (pos * w / dataCopy.length); 103 } 104 105 private int toYCoodinate(byte data, int height) { 106 int amp = (int) data; 107 return (int) ((amp - 128) * (height / 255.0) * -1 + 50);//タイトルバーで隠れるので少し下げる 108 } 109} 110
###発生した課題
波形は正常に表示されているものの、想定してたものよりもFPSが非常に小さい。(おおよそ10FPS?)
試したこと
runメソッド内での各ステップごとの所要時間、およびpaintComponentメソッドの処理時間をログで表示したら以下のようになりました。特にAudioInputStream.read()の所要時間がおおよそ140ミリ秒であるか0秒であるかのどちらかであり、30ミリ秒で完結すると思っていたがかけ離れたものとなりました。ここには載せていないが、録音間隔を10ミリ秒、50ミリ秒にした場合でも同じ結果が得られました(「AudioInputStream.read()の所要時間」が「0秒」になっているループ数は異なった)。
恐らく140ミリ秒がAudioInputStream.read()の所要時間の限界であるように思えるのですが、本当にそうでしょうか。なにか改善点があったらお願いします。
[Repeint] Loop 1: 4 [Main Loop] Loop 1: 142 0 1 [Main Loop] Loop 2: 0 0 0 [Main Loop] Loop 3: 0 0 0 [Main Loop] Loop 4: 0 0 0 [Repeint] Loop 5: 3 [Repeint] Loop 5: 2 [Main Loop] Loop 5: 137 0 0 [Main Loop] Loop 6: 1 0 0 [Main Loop] Loop 7: 0 0 0 [Main Loop] Loop 8: 1 0 0 [Repeint] Loop 9: 4 [Repeint] Loop 9: 4 [Main Loop] Loop 9: 137 0 0 [Main Loop] Loop 10: 1 0 0 [Main Loop] Loop 11: 0 0 0 [Main Loop] Loop 12: 1 0 0 [Main Loop] Loop 13: 0 0 0 [Repeint] Loop 14: 4 [Main Loop] Loop 14: 139 0 0 [Main Loop] Loop 15: 0 0 2 [Repeint] Loop 15: 2 [Main Loop] Loop 16: 0 0 0 [Main Loop] Loop 17: 0 0 0 [Repeint] Loop 18: 1 [Main Loop] Loop 18: 140 0 0 [Main Loop] Loop 19: 1 0 0 [Main Loop] Loop 20: 0 0 0 (以下文字数制限のため略)
追記1
System.nanoTimeを使用した場合はこうなりました。
[Repeint] Loop 1: 3.7141 [Main Loop] Loop 1: 147.1323 0.0092 0.4591 [Main Loop] Loop 2: 0.1487 0.0016 0.0283 [Main Loop] Loop 3: 0.111 0.0018 0.0112 [Main Loop] Loop 4: 0.0723 0.0022 0.0071 [Repeint] Loop 5: 1.0374 [Repeint] Loop 5: 0.9224 [Main Loop] Loop 5: 125.0524 0.0281 0.1598 [Main Loop] Loop 6: 0.3004 0.0086 0.1049 [Main Loop] Loop 7: 0.2658 0.0218 0.0207 [Main Loop] Loop 8: 0.2519 0.0071 0.0212 [Repeint] Loop 9: 3.4221 [Repeint] Loop 9: 0.9553 [Main Loop] Loop 9: 139.1244 0.0095 0.1027 [Main Loop] Loop 10: 0.1454 0.0037 0.0404 [Main Loop] Loop 11: 0.1752 0.0071 0.0256 [Main Loop] Loop 12: 0.1436 0.0029 0.0097 [Repeint] Loop 13: 1.3418 [Repeint] Loop 13: 1.0709 [Main Loop] Loop 13: 139.2908 0.013 0.1875 [Main Loop] Loop 14: 0.3437 0.0318 0.1382 [Main Loop] Loop 15: 0.327 0.0083 0.0256 [Main Loop] Loop 16: 0.2782 0.025 0.0255 [Main Loop] Loop 17: 0.3119 0.0083 0.0496 [Repeint] Loop 18: 3.5176 [Repeint] Loop 18: 2.3505 [Main Loop] Loop 18: 138.5742 0.0124 0.1887 [Main Loop] Loop 19: 0.339 0.0096 0.1255 [Main Loop] Loop 20: 0.3278 0.0071 0.0243 (以下文字数制限のため略)
補足情報(FW/ツールのバージョンなど)
Eclipse IDE for Enterprise Java and Web Developers (includes Incubating components)
Version: 2021-03 (4.19.0)
Build id: 20210312-0638
java 16.0.1 2021-04-20
Java(TM) SE Runtime Environment (build 16.0.1+9-24)
Java HotSpot(TM) 64-Bit Server VM (build 16.0.1+9-24, mixed mode, sharing)
デバイス名 LAPTOP-L49P9QG6
プロセッサ Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz 2.59 GHz
実装 RAM 16.0 GB (15.9 GB 使用可能)
システムの種類 64 ビット オペレーティング システム、x64 ベース プロセッサ
ペンとタッチ このディスプレイでは、ペン入力とタッチ入力は利用できません
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。