-1

Image of ProgramI'm working on a Java Swing application that includes a music equalizer. The application is supposed to allow users to select an MP3 file and visualize the audio levels in real-time. However, when I select an MP3 file, the application does nothing, and no audio is played

I also added a sample.mp3 (private static final String DEFAULT_MP3_PATH = "sample.mp3") but the issue persists.

import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.io.*;
import javazoom.jl.player.*;
// import javazoom.jl.decoder.*;

public class MusicEqualizer extends JFrame {
    private static final int BANDS = 32;
    private static final int MAX_HEIGHT = 100;
    private static final int FFT_SIZE = 1024;
    private int[] levels = new int[BANDS];
    private Color[] colors = new Color[BANDS];
    private Player player;
    private byte[] buffer;
    private double[] fftData;
    private boolean isPlaying = false;

    public MusicEqualizer() {
        setTitle("Music Equalizer");
        setSize(800, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        initializeColors();
        buffer = new byte[FFT_SIZE * 2];
        fftData = new double[FFT_SIZE * 2];

        JPanel equalizerPanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                drawEqualizer(g);
            }
        };
        add(equalizerPanel);

        JButton selectFileButton = new JButton("Select File");
        selectFileButton.addActionListener(e -> selectFile());
        add(selectFileButton, BorderLayout.SOUTH);
    }

    private void initializeColors() {
        for (int i = 0; i < BANDS; i++) {
            float hue = (float) i / BANDS;
            colors[i] = Color.getHSBColor(hue, 1.0f, 1.0f);
        }
    }

    private void drawEqualizer(Graphics g) {
        int width = getWidth();
        int bandWidth = width / BANDS;

        for (int i = 0; i < BANDS; i++) {
            int x = i * bandWidth;
            int y = getHeight() - levels[i];
            int height = levels[i];

            g.setColor(colors[i]);
            g.fillRect(x, y, bandWidth - 1, height);
        }
    }

    private void updateLevels(InputStream is) {
        try {
            int bytesRead = is.read(buffer, 0, buffer.length);
    
            if (bytesRead > 0) {
                for (int i = 0; i < FFT_SIZE * 2; i++) {
                    fftData[i] = (i < bytesRead) ? buffer[i] / 128.0 : 0.0;
                }
    
                fft(fftData);
    
                for (int i = 0; i < BANDS; i++) {
                    double sum = 0;
                    for (int j = i * 16; j < (i + 1) * 16 && j < FFT_SIZE; j++) {
                        sum += Math.sqrt(fftData[2 * j] * fftData[2 * j] + fftData[2 * j + 1] * fftData[2 * j + 1]);
                    }
                    levels[i] = (int) Math.min(MAX_HEIGHT, sum / 16 * MAX_HEIGHT);
                }
    
                repaint();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }    


    private void fft(double[] x) {
        int n = x.length / 2;

        // bit reversal
        int j = 0;
        for (int i = 0; i < n - 1; i++) {
            if (i < j) {
                double temp = x[2*i];
                x[2*i] = x[2*j];
                x[2*j] = temp;
                temp = x[2*i+1];
                x[2*i+1] = x[2*j+1];
                x[2*j+1] = temp;
            }
            int k = n / 2;
            while (k <= j) {
                j -= k;
                k /= 2;
            }
            j += k;
        }

        // FFT
        for (int l = 2; l <= n; l *= 2) {
            double angle = -2 * Math.PI / l;
            double wr = Math.cos(angle);
            double wi = Math.sin(angle);
            for (int i = 0; i < n; i += l) {
                double tr = 1.0, ti = 0.0;
                for (int m = 0; m < l / 2; m++) {
                    int p = i + m;
                    int q = i + m + l / 2;
                    double sr = x[2*q] * tr - x[2*q+1] * ti;
                    double si = x[2*q] * ti + x[2*q+1] * tr;
                    x[2*q] = x[2*p] - sr;
                    x[2*q+1] = x[2*p+1] - si;
                    x[2*p] += sr;
                    x[2*p+1] += si;
                    double tr_temp = tr;
                    tr = tr * wr - ti * wi;
                    ti = tr_temp * wi + ti * wr;
                }
            }
        }
    }

    private void selectFile() {
        JFileChooser fileChooser = new JFileChooser();
        FileNameExtensionFilter filter = new FileNameExtensionFilter("MP3 Files", "mp3");
        fileChooser.setFileFilter(filter);
        
        int result = fileChooser.showOpenDialog(this);
        
        if (result == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            playFile(selectedFile);
        }
    }

    private void playFile(File file) {
        stopPlayback();
        try {
            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fis);
            player = new Player(bis);
    
            new Thread(() -> {
                try {
                    isPlaying = true;
                    player.play();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    isPlaying = false;
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
            new Thread(() -> {
                try {
                    while (isPlaying && !player.isComplete()) {
                        updateLevels(bis);
                        Thread.sleep(20);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
    
        } catch (Exception e) {
            e.printStackTrace();
        }
    }    

    private void stopPlayback() {
        isPlaying = false;
        if (player != null) {
            player.close();
            player = null;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            MusicEqualizer equalizer = new MusicEqualizer();
            equalizer.setVisible(true);
        });
    }
}
5
  • You're going to need to coordinate the playing thread(s) with the Event Dispatch Thread. Study the excellent documentation for SwingWorker and use one
    – g00se
    Commented Jul 2 at 8:53
  • 1
    You have two threads (the Player and the fft thread) both reading from a single InputStream. That means that neither of these two threads will be able to completely read the data contained in the InputStream and therefore both will read corrupt data. Commented Jul 2 at 8:57
  • And: MP3 is a compressed format. Trying to do an FFT on that compressed data stream does not produce meaningfull results. You must decode that data first. Commented Jul 2 at 8:58
  • Oracle has a helpful sound tutorial. The list of supported input file formats is on the second page. Commented Jul 2 at 13:15
  • Downvote because the question does not include much description of how you are trying to achieve your goal or what you tried. A lot of details go into writing even such a seemingly simple application. For instance you should not be calling repaint() from updateLevels because it is not running on the GUI thread (AWT-EventQueue-0).
    – masterxilo
    Commented Jul 13 at 14:15

0

Browse other questions tagged or ask your own question.