3.3.6 Experimenting with Music in Java

3.3.6 Experimenting with Music in Java

[wpfilebase tag=file id=128 tpl=supplement /]

Let’s try making chords in Java as we did in C++. We’ll give you the code for this first exercise to get you started, and then you can try some exercises on your own. The “Chords in Java” program plays a chord selected from the list shown in Figure 3.54. The program contains two Java class files, one called Chord and the other called ChordApp. The top level class (i.e., the one that includes the main function) is the ChordApp class. The ChordApp class is a subclass of the JPanel, which is a generic window container. The JPanel provides functionality to display a window as a user interface. The constructor of the ChordApp class creates a list of radio buttons and displays the window with these options (Figure 3.54). When the user selects a type of chord, the method playChord() is called through the Chord class (line 138).

Figure 3.54  Interface for Java chord-playing program
Figure 3.54 Interface for Java chord-playing program

The ChordApp class contains the method playChord (line 7), which is a variation of the code shown in the MATLAB section. In the playChord method, the ChordApp object creates a Chord object, initializing it with the array scale, which contains the list of notes to be played in the chord. These notes are summed in the Chord class in lines 46 to 48.

 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;

 public class ChordApp extends JPanel implements ActionListener {

     public static void playChord(String command)
     {/**Method that decides which Chord to play */
         float[] major7th = {0, 4, 7, 11};
         float[] minor7th = {0, 3, 7, 10};
         float[] domin7th = {0, 4, 7, 10};
         float[] dimin7th = {0, 3, 6, 10};
         float[] majorTri = {0, 4, 7};
         float[] minorTri = {0, 3, 7};
         float[] augmeTri = {0, 4, 8};
         float[] diminTri = {0, 3, 6};

         float[] scale;

         if      (command == "major7th")
             scale = major7th;
         else if (command == "minor7th")
             scale = minor7th;
         else if (command == "domin7th")
             scale = domin7th;
         else if (command == "dimin7th")
             scale = dimin7th;
         else if (command == "majorTri")
             scale = majorTri;
         else if (command == "minorTri")
             scale = minorTri;
         else if (command == "augmeTri")
             scale = augmeTri;
         else
             scale = diminTri;

         float startnote = 220*(2^((2+3)/12));

         for(int i=0;i<scale.length;i++){
             scale[i] = scale[i]/12;
             scale[i] = (float)Math.pow(2,scale[i]);
             scale[i] = startnote * scale[i];
         }

         //once we know which Chord to play, we call the Chord function
         Chord chord = new Chord(scale);
         chord.play();
     }

     public ChordApp() {
         super(new BorderLayout());

         try {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
             SwingUtilities.updateComponentTreeUI(this);
         } catch (Exception e) {
             System.err.println(e);
         }

         JRadioButton maj7thButton = new JRadioButton("Major Seventh");
         maj7thButton.setActionCommand("major7th");

         JRadioButton min7thButton = new JRadioButton("Minor Seventh");
         min7thButton.setActionCommand("minor7th");

         JRadioButton dom7thButton = new JRadioButton("Dominant Seventh");
         dom7thButton.setActionCommand("domin7th");

         JRadioButton dim7thButton = new JRadioButton("Diminished Seventh");
         dim7thButton.setActionCommand("dimin7th");

         JRadioButton majTriButton = new JRadioButton("Major Triad");
         majTriButton.setActionCommand("majorTri");

         JRadioButton minTriButton = new JRadioButton("Minor Triad");
         minTriButton.setActionCommand("minorTri");

         JRadioButton augTriButton = new JRadioButton("Augmented Triad");
         augTriButton.setActionCommand("augmeTri");

         JRadioButton dimTriButton = new JRadioButton("Diminished Triad");
         dimTriButton.setActionCommand("diminTri");

         ButtonGroup group = new ButtonGroup();
         group.add(maj7thButton);
         group.add(min7thButton);
         group.add(dom7thButton);
         group.add(dim7thButton);
         group.add(majTriButton);
         group.add(minTriButton);
         group.add(augTriButton);
         group.add(dimTriButton);

         maj7thButton.addActionListener(this);
         min7thButton.addActionListener(this);
         dom7thButton.addActionListener(this);
         dim7thButton.addActionListener(this);
         majTriButton.addActionListener(this);
         minTriButton.addActionListener(this);
         augTriButton.addActionListener(this);
         dimTriButton.addActionListener(this);

         JPanel radioPanel = new JPanel(new GridLayout(0, 1));
         radioPanel.add(maj7thButton);
         radioPanel.add(min7thButton);
         radioPanel.add(dom7thButton);
         radioPanel.add(dim7thButton);
         radioPanel.add(majTriButton);
         radioPanel.add(minTriButton);
         radioPanel.add(augTriButton);
         radioPanel.add(dimTriButton);

         add(radioPanel, BorderLayout.LINE_START);
         setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
     }

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

     private static void ShowWindow() {
         JFrame frame = new JFrame("Chords App");
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

         JComponent newContentPane = new ChordApp();
         newContentPane.setOpaque(true); //content panes must be opaque
         frame.setContentPane(newContentPane);

         frame.pack();
         frame.setVisible(true);
     }
     /** Listens to the radio buttons. */
     public void actionPerformed(ActionEvent e) {
         ChordApp.playChord(e.getActionCommand());
     }
 }

Algorithm 3.3 ChordApp class

 
 
 import javax.sound.sampled.AudioFormat;
 import javax.sound.sampled.AudioSystem;
 import javax.sound.sampled.SourceDataLine;
 import javax.sound.sampled.LineUnavailableException;
 
 public class Chord {
     float[] Scale;
     
     public Chord(float[] scale) {
         Scale=scale;
     }
     
     public void play() {
         try {
             makeChord(Scale);
         } catch (LineUnavailableException lue) {
             System.out.println(lue);
         }
     }
     
     private void makeChord(float[] scale)
     throws LineUnavailableException
     {
         int freq = 44100;
         float[] x=new float[(int)(freq)];
         
         byte[] buf;
         AudioFormat audioF;
         
         for(int i=0;i<x.length;i++){
             x[i]=(float)(i+1)/freq;
         }
         
         buf = new byte[1];
         audioF = new AudioFormat(freq,8,1,true,false);
 
         SourceDataLine sourceDL = AudioSystem.getSourceDataLine(audioF);
         sourceDL = AudioSystem.getSourceDataLine(audioF);
         sourceDL.open(audioF);
         sourceDL.start();        
 
         for (int j=0;j<x.length;j++){
             buf[0]= 0;
             for(int i=0;i<scale.length;i++){
               buf[0]=(byte)(buf[0]+(Math.sin((2*Math.PI*scale[i])*x[j])*10.0)) 
             }
             sourceDL.write(buf,0,1);
         }

         sourceDL.drain();
         sourceDL.stop();
         sourceDL.close();
     }
 }

Algorithm 3.4  Chord class

[wpfilebase tag=file id=87 tpl=supplement /]

[wpfilebase tag=file id=85 tpl=supplement /]

As another exercise, you can try to play and compare equal vs. just tempered scales, the same program exercise linked in the C++ section above.

The last exercise associated with this section, you’re asked to create a metronome-type object that creates a beat sound according to the user’s specifications for tempo. You may want to borrow something similar to the code in the ChordApp class to create the graphical user interface.

[separator top=”1″ bottom=”0″ style=”none”]