HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaModerate

Using sounds in Java

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
usingjavasounds

Problem

I'm trying to apply sound today, and the goal in mind was a simple violin tuner. The actionListener seems repetitive/ How might I optimize it (what I tried just broke everything)? I also noticed the sounds bleed into each other. I don't mind that so much for the different keys (though I'm thinking of a toggle option for this) but it also is the case for the same key, which is undesirable. I'm not sure how to handle that.

```
/* Author: Luigi Vincent
A simple violin tuner, emits G, D, A, and E sounds to facilitate violin tuning
*/

import javax.swing.*;
import javax.sound.sampled.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;

public class ViolinTuner {
public static void main(String[] args) {
JFrame frame = new JFrame("Violin Tuner");
// get and set icon for the program
ImageIcon icon = new ImageIcon("Images/Icon.png");
frame.setIconImage(icon.getImage());
// Buttons
final JButton G_KEY = new JButton("G");
final JButton D_KEY = new JButton("D");
final JButton A_KEY = new JButton("A");
final JButton E_KEY = new JButton("E");
// Listener to play sounds on click
ActionListener violinSounds = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == G_KEY) {
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("Sounds/G.wav").getAbsoluteFile());
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start();
}catch(Exception x) { x.printStackTrace(); }
}
else if (e.getSource() == D_KEY) {
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("Sounds/D.wav").getAbsoluteFile());

Solution

Layout

Calling .setSize() with fixed dimensions isn't portable. For example, this is what happens on Mac OS X:

Instead, call frame.pack() to automatically set the frame size according to its contents.

If you want the 2 × 2 layout, then use a suitable LayoutManager — for example, p.setLayout(new GridLayout(2, 0, 10, 6));

Don't Repeat Yourself

The code is awfully repetitive. You should avoid repeating yourself, since repetition makes maintenance difficult: cut-and-paste programming leads to cut-and-paste bugs. I recommend using an Enum to represent the four notes.

Explicitness

It's bad practice to catch (Exception x). I have no clue what kind of exception would likely cause the flow of execution to jump to the exception handler. You, as the author, might intend for certain exceptions to be caught, but you don't know what will actually happen. Starting with Java 7, you can list multiple exceptions to be handled by the same catch block, and that's what I recommend that you do.

Avoid overuse of wildcard imports. There exists a small probability that a future version of some package could add a class that clashes and breaks your program. Mostly, using too many wildcard imports makes it hard for human maintainers to resolve identifiers — the compiler may be good at searching the classpath, but I'm not. My suggested guidelines are:

  • It's OK to use wildcard imports with the standard Java packages that almost every Java programmer is familiar with (such as java.io. or java.util.).



  • It's OK to use one wildcard import per file, maybe two, but not much more.



  • If in doubt, import individual classes explicitly.



  • List your imports alphabetically.



By the way, you never used anything in java.awt.*.

Suggested implementation

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.*;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.ImageIcon;
import javax.swing.SwingUtilities;

public class ViolinTuner {
    private static enum Note {
        G, D, A, E;

        public final File file;

        Note() {
            this.file = new File("Sounds", this.name() + ".wav").getAbsoluteFile();
        }
    }

    private static JButton makeJButton(final Note note) {
        JButton button = new JButton(note.name());
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(note.file);
                    Clip clip = AudioSystem.getClip();
                    clip.open(audioInputStream);
                    clip.start();
                } catch (IOException | UnsupportedAudioFileException | LineUnavailableException x) {
                    x.printStackTrace();
                }
            }
        });
        return button;
    }

    private static void createAndShowGUI() {
        JFrame frame = new JFrame("Violin Tuner");
        frame.setIconImage(new ImageIcon("Images/Icon.png").getImage());

        // buttons to panel
        JPanel notePanel = new JPanel(new GridLayout(2, 0, 8, 4));
        notePanel.setBorder(BorderFactory.createEmptyBorder(4, 8, 4, 8));
        for (Note note : Note.values()) {
            notePanel.add(makeJButton(note));
        }

        // Component to impose a minimum width on the JFrame to ensure that the
        // window title is not truncated
        JPanel widener = new JPanel();
        widener.setPreferredSize(new Dimension(250, 0));

        // Panels to frame
        frame.setLayout(new BorderLayout());
        frame.add(notePanel, BorderLayout.CENTER);
        frame.add(widener, BorderLayout.SOUTH);
        frame.pack();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        }
    }
}

Code Snippets

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.*;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.ImageIcon;
import javax.swing.SwingUtilities;

public class ViolinTuner {
    private static enum Note {
        G, D, A, E;

        public final File file;

        Note() {
            this.file = new File("Sounds", this.name() + ".wav").getAbsoluteFile();
        }
    }

    private static JButton makeJButton(final Note note) {
        JButton button = new JButton(note.name());
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(note.file);
                    Clip clip = AudioSystem.getClip();
                    clip.open(audioInputStream);
                    clip.start();
                } catch (IOException | UnsupportedAudioFileException | LineUnavailableException x) {
                    x.printStackTrace();
                }
            }
        });
        return button;
    }

    private static void createAndShowGUI() {
        JFrame frame = new JFrame("Violin Tuner");
        frame.setIconImage(new ImageIcon("Images/Icon.png").getImage());

        // buttons to panel
        JPanel notePanel = new JPanel(new GridLayout(2, 0, 8, 4));
        notePanel.setBorder(BorderFactory.createEmptyBorder(4, 8, 4, 8));
        for (Note note : Note.values()) {
            notePanel.add(makeJButton(note));
        }

        // Component to impose a minimum width on the JFrame to ensure that the
        // window title is not truncated
        JPanel widener = new JPanel();
        widener.setPreferredSize(new Dimension(250, 0));

        // Panels to frame
        frame.setLayout(new BorderLayout());
        frame.add(notePanel, BorderLayout.CENTER);
        frame.add(widener, BorderLayout.SOUTH);
        frame.pack();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        }
    }
}

Context

StackExchange Code Review Q#57502, answer score: 11

Revisions (0)

No revisions yet.