Metronome: Difference between revisions

3,388 bytes added ,  10 months ago
New post with audible and visual indications of the metronome timing. In addition to an existing program with neither of these indications.
m (Minor code improvements.)
(New post with audible and visual indications of the metronome timing. In addition to an existing program with neither of these indications.)
Line 1,028:
metronome1.start();
}
}
</syntaxhighlight>
 
===AudioVisual===
This example provides an audible and visual indications of the metronome timing.
 
It uses a timing loop to ensure that its timing is reliable in the long term.
<syntaxhighlight lang="java">
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
 
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
 
public final class MetronomeTask {
 
public static void main(String[] aArgs) {
EventQueue.invokeLater( () -> { new Metronome(60, 4, 1).start(); } );
}
 
}
 
final class Metronome extends JPanel {
public Metronome(int aBeatsPerMinute, int aMeasure, int aDurationInMinutes) {
beatsPerMinute = aBeatsPerMinute; measure = aMeasure; durationInMinutes = aDurationInMinutes;
SoundEffect.initialise();
createAndShowGUI();
}
public void start() {
executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(provideService, 1, 1, TimeUnit.SECONDS);
}
private void createAndShowGUI() {
JFrame.setDefaultLookAndFeelDecorated(true);
frame = new JFrame("Metronome");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setIconImage( new ImageIcon("./metronomeJava.png").getImage() );
frame.add(createPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
}
private JPanel createPanel() {
setPreferredSize( new Dimension(800, 600) );
setBackground(Color.CYAN);
return this;
}
private JFrame frame;
private ScheduledExecutorService executorService;
private int beatsPerMinute, measure, durationInMinutes, counter;
private Runnable provideService = () -> {
if ( counter < durationInMinutes * beatsPerMinute ) {
counter++;
if ( counter % measure != 0 ) {
SoundEffect.Tick.play();
if ( getBackground() != Color.PINK ) {
setBackground(Color.PINK);
} else {
setBackground(Color.CYAN);
}
} else {
SoundEffect.Tock.play();
setBackground(Color.ORANGE);
}
} else {
executorService.shutdown();
frame.dispose();
Runtime.getRuntime().exit(0);
}
};
}
 
enum SoundEffect {
Tick("./metronomeTickJava.wav"), Tock("./metronomeTockJava.wav");
public static void initialise() {
values();
}
public void play() {
if ( clip.isRunning() ) {
clip.stop();
}
clip.setFramePosition(0);
clip.start();
}
private SoundEffect(String soundFileName) {
URL url = getClass().getClassLoader().getResource(soundFileName);
try ( AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url) ) {
clip = AudioSystem.getClip();
clip.open(audioInputStream);
} catch (IOException | LineUnavailableException | UnsupportedAudioFileException ex) {
ex.printStackTrace();
}
}
private Clip clip;
}
</syntaxhighlight>
908

edits