3

私のコード スニペットを見てください。何が問題なのですか?

class WaveformPanel extends JPanel {

        Timer graphTimer = null;
        AudioInfo helper = null;

        WaveformPanel() {
            setPreferredSize(new Dimension(200, 80));
            setBorder(BorderFactory.createLineBorder(Color.BLACK));
            graphTimer = new Timer(15, new TimerDrawing());
        }

        /**
         * 
         */
        private static final long serialVersionUID = 969991141812736791L;
        protected final Color BACKGROUND_COLOR = Color.white;
        protected final Color REFERENCE_LINE_COLOR = Color.black;
        protected final Color WAVEFORM_COLOR = Color.red;

        protected void paintComponent(Graphics g) {

            super.paintComponent(g);

            int lineHeight = getHeight() / 2;
            g.setColor(REFERENCE_LINE_COLOR);
            g.drawLine(0, lineHeight, (int) getWidth(), lineHeight);

            if (helper == null) {
                return;
            }

            drawWaveform(g, helper.getAudio(0));

        }

        protected void drawWaveform(Graphics g, int[] samples) {

            if (samples == null) {
                return;
            }

            int oldX = 0;
            int oldY = (int) (getHeight() / 2);
            int xIndex = 0;

            int increment = helper.getIncrement(helper
                    .getXScaleFactor(getWidth()));
            g.setColor(WAVEFORM_COLOR);

            int t = 0;

            for (t = 0; t < increment; t += increment) {
                g.drawLine(oldX, oldY, xIndex, oldY);
                xIndex++;
                oldX = xIndex;
            }

            for (; t < samples.length; t += increment) {
                double scaleFactor = helper.getYScaleFactor(getHeight());
                double scaledSample = samples[t] * scaleFactor;
                int y = (int) ((getHeight() / 2) - (scaledSample));
                g.drawLine(oldX, oldY, xIndex, y);

                xIndex++;
                oldX = xIndex;
                oldY = y;
            }
        }

        public void setAnimation(boolean turnon) {
            if (turnon) {
                graphTimer.start();
            } else {
                graphTimer.stop();
            }
        }

        class TimerDrawing implements ActionListener {

            @Override
            public void actionPerformed(ActionEvent e) {

                byte[] bytes = captureThread.getTempBuffer();

                if (helper != null) {
                    helper.setBytes(bytes);
                } else {
                    helper = new AudioInfo(bytes);
                }
                repaint();
            }
        }

    }

親クラスから WaveFormPanel の setAnimation を呼び出しています。アニメーションが開始すると、何も描画されずにフリーズします。解決策を教えてください。

ありがとうミヒル・パレク

4

2 に答える 2

4

は内で をjava.swingx.Timer呼び出します。問題は、何がレンダリングに時間がかかっているかということです。呼び出しがヘルプの構成である可能性がありますが、ペイントしようとしているデータの共有量にすぎないと思います。ActionPerformedEDTcaptureThread.getTempBuffer

最近いじっていると、波形の処理にかなり時間がかかります。

1 つの提案は、ペイントするサンプルの数を減らすことです。それぞれをペイントするのではなく、コンポーネントの幅に応じて、1 つおきまたは 4 つおきのサンプル ポイントをペイントします。あなたはまだ同じ冗談を得るはずですが、すべての作業はありません...

更新しました

すべてのサンプル、2.18 秒

すべてのサンプル

4 サンプルごと、0.711 秒

ここに画像の説明を入力

8 サンプルごと、0.450 秒

ここに画像の説明を入力

タイマーに応答してペイントするのではなく、データのバッチに応答してペイントする必要があるかもしれません。

ローダースレッドにはデータの「チャンク」があるため、それをペイントすることができます。

HoverCraftFullOfEels が示唆したように、これを最初に BufferedImage にペイントしてから、それを画面にペイントできます...

SwingWorkerがこれを実現できるかもしれません

更新しました

これは、上記のサンプルをペイントするために使用するコードです。

// Samples is a 2D int array (int[][]), where the first index is the channel, the second is the sample for that channel
if (samples != null) {

    Graphics2D g2d = (Graphics2D) g;

    int length = samples[0].length;

    int width = getWidth() - 1;
    int height = getHeight() - 1;

    int oldX = 0;
    int oldY = height / 2;
    int frame = 0;

    // min, max is the min/max range of the samples, ie the highest and lowest samples
    int range = max + (min * -2);
    float scale = (float) height / (float) range;

    int minY = Math.round(((height / 2) + (min * scale)));
    int maxY = Math.round(((height / 2) + (max * scale)));

    LinearGradientPaint lgp = new LinearGradientPaint(
            new Point2D.Float(0, minY),
            new Point2D.Float(0, maxY),
            new float[]{0f, 0.5f, 1f},
            new Color[]{Color.BLUE, Color.RED, Color.BLUE});
    g2d.setPaint(lgp);
    for (int sample : samples[0]) {

        if (sample % 64 == 0) {

            int x = Math.round(((float) frame / (float) length) * width);
            int y = Math.round((height / 2) + (sample * scale));

            g2d.drawLine(oldX, oldY, x, y);

            oldX = x;
            oldY = y;

        }

        frame++;

    }

}

ストリームを使用しAudioStreamて Wav ファイルをロードし、2D サンプルを生成します。

于 2012-08-22T05:25:24.377 に答える
3

メソッド内から呼び出されているウェーブ描画コードは、paintComponent(...)思ったよりも時間がかかっており、Swing ペインティングと EDT の両方を拘束していると思います。

これが私のコードである場合、波を BufferedImagesに一度描画し、これらの画像から ImageIcons を作成し、Swing Timer でアイコンを交換することを検討します。

于 2012-08-22T05:24:16.970 に答える