org.monome.pages.MachineDrumInterfacePage.java Source code

Java tutorial

Introduction

Here is the source code for org.monome.pages.MachineDrumInterfacePage.java

Source

/*
 *  MachineDrumInterfacePage.java
 * 
 *  Copyright (c) 2008, Tom Dinchak
 * 
 *  This file is part of Pages.
 *
 *  Pages is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  Pages is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  You should have received a copy of the GNU General Public License
 *  along with Pages; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

package org.monome.pages;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.sound.midi.MidiMessage;
import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import org.apache.commons.lang.StringEscapeUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.cloudgarden.layout.AnchorConstraint;
import com.cloudgarden.layout.AnchorLayout;

/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
/**
 * The Machine Drum Interface page.  Usage information is available at:
 * 
 * http://code.google.com/p/monome-pages/wiki/MachineDrumInterfacePage
 *   
 * @author Tom Dinchak
 *
 */
public class MachineDrumInterfacePage implements Page, ActionListener {

    /**
     * The MonomeConfiguration object this page belongs to
     */
    MonomeConfiguration monome;

    /**
     * The index of this page (the page number) 
     */
    private int index;

    /**
     * The GUI for this page's configuration
     */
    private JPanel panel;
    private JLabel jLabel1;

    /**
     * The Add MIDI Output button
     */
    private JButton addMidiOutButton;

    /**
     * The Speed label 
     */
    private JLabel speedLabel;

    /**
     * The Update Preferences button
     */
    private JButton updatePrefsButton;

    /**
     * The Speed text field
     */
    private JTextField speedTF;

    /**
     * The MIDI device to send to the MachineDrum on
     */
    private Receiver recv;

    /**
     * The name of the selected MIDI device
     */
    private String midiDeviceName;

    /**
     * morph_machines[machine_number] - 1 if machine_number machine should be sent random parameter changes
     */
    private int[] morph_machines = new int[16];

    /**
     * morph_params[param_number] - 1 if the param_number paramater should be sent random changes 
     */
    private int[] morph_params = new int[24];

    /**
     * fx_morph[fx_number] - 1 if the fx_number fx unit should be sent random parameter changes, [0] = echo, [1] = gate, [2] = eq, [3] = compressor
     */
    private int[] fx_morph = new int[4];

    /**
     * true randomly enables and disables morph_machines and morph_params
     */
    private boolean auto_morph = false;

    /**
     * Random number generator 
     */
    private Random generator;

    /**
     * Utility class for sending MIDI messages to the MachineDrum 
     */
    private MachineDrum machine_drum;

    /**
     * A counter for MIDI clock sync ticks 
     */
    private int ticks;

    /**
     * How often random param changes are sent. 
     */
    private int speed = 100;

    /**
     * The name of the page 
     */
    private String pageName = "Machine Drum Interface";
    private JLabel pageNameLBL;

    /**
     * @param monome The MonomeConfiguration this page belongs to
     * @param index The index of this page (the page number)
     */
    public MachineDrumInterfacePage(MonomeConfiguration monome, int index) {
        this.machine_drum = new MachineDrum();
        this.monome = monome;
        this.index = index;
        this.generator = new Random();
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#getName()
     */
    public String getName() {
        return pageName;
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#setName()
     */
    public void setName(String name) {
        this.pageName = name;
        this.pageNameLBL.setText("Page " + (this.index + 1) + ": " + pageName);
        this.monome.setJMenuBar(this.monome.createMenuBar());
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#handlePress(int, int, int)
     */
    public void handlePress(int x, int y, int value) {
        // only act on press events
        if (value == 1) {
            // top two rows, toggle morph_machines on and off
            if (y < 2) {
                int machine_num = getMachineNum(x, y);
                if (morph_machines[machine_num] == 1) {
                    morph_machines[machine_num] = 0;
                    this.monome.led(x, y, 0, this.index);
                } else {
                    morph_machines[machine_num] = 1;
                    this.monome.led(x, y, 1, this.index);
                }
                // next 3 rows, toggle morph_params on and off
            } else if (y < 5) {
                int param_num = getMachineNum(x, y - 2);
                if (morph_params[param_num] == 1) {
                    morph_params[param_num] = 0;
                    this.monome.led(x, y, 0, this.index);
                } else {
                    morph_params[param_num] = 1;
                    this.monome.led(x, y, 1, this.index);
                }
                // 6th row, initialize new kits
            } else if (y == 5) {
                machine_drum.initKit(recv, x);
                // 7th row, kit load and save
            } else if (y == 6) {
                System.out.println("kit function");
                if (x < 4) {
                    machine_drum.sendKitLoad(recv, x);
                } else {
                    machine_drum.sendKitSave(recv, x - 4);
                }
                // last row, auto morph toggle and fx morph toggles
            } else if (y == 7) {
                if (x == 0) {
                    if (auto_morph == false) {
                        auto_morph = true;
                        this.monome.led(x, y, 1, this.index);
                    } else {
                        auto_morph = false;
                        this.monome.led(x, y, 0, this.index);
                    }
                } else if (x > 0 && x < 5) {
                    if (fx_morph[x - 1] == 0) {
                        fx_morph[x - 1] = 1;
                    } else {
                        fx_morph[x - 1] = 0;
                    }
                    this.monome.led(x, y, fx_morph[x - 1], this.index);
                }
            }
        }
    }

    /**
     * Translate monome x/y to a MachineDrum machine number
     * 
     * @param x The x coordinate on the monome
     * @param y The y coordinate on the monome
     * @return The MachineDrum machine number
     */
    public int getMachineNum(int x, int y) {
        return (y * 8) + x;
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#handleReset()
     */
    public void handleReset() {
        // reset ticks to 0 when clock is reset
        ticks = 0;
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#handleTick()
     */
    public void handleTick() {
        // count from 0 to 5 and reset
        if (ticks == 6) {
            ticks = 0;
        }

        // turn off and on random machines/params to morph
        if (auto_morph == true && generator.nextInt(this.speed) == 1) {
            int machine_num = generator.nextInt(12) + 2;
            int param_num = generator.nextInt(24);
            int x_m = machine_num % 8;
            int y_m = machine_num / 8;
            int x_p = param_num % 8;
            int y_p = (param_num / 8) + 2;

            if (morph_machines[machine_num] == 1) {
                morph_machines[machine_num] = 0;
                this.monome.led(x_m, y_m, 0, this.index);
            } else {
                morph_machines[machine_num] = 1;
                this.monome.led(x_m, y_m, 1, this.index);
            }
            if (morph_params[param_num] == 1) {
                morph_params[param_num] = 0;
                this.monome.led(x_p, y_p, 0, this.index);
            } else {
                morph_params[param_num] = 1;
                this.monome.led(x_p, y_p, 1, this.index);
            }
        }

        // send a param change to the echo effect
        if (fx_morph[0] == 1 && ticks == 0) {
            machine_drum.sendFxParam(recv, "echo", generator.nextInt(8), generator.nextInt(127));
        }

        // send a param change to the gate effect
        if (fx_morph[1] == 1 && ticks == 1) {
            machine_drum.sendFxParam(recv, "gate", generator.nextInt(8), generator.nextInt(127));
        }

        // send a param change to the eq effect
        if (fx_morph[2] == 1 && ticks == 2) {
            machine_drum.sendFxParam(recv, "eq", generator.nextInt(8), generator.nextInt(127));
        }

        // send a param change to the compressor effect
        if (fx_morph[3] == 1 && ticks == 3) {
            machine_drum.sendFxParam(recv, "compressor", generator.nextInt(8), generator.nextInt(127));
        }

        // send random parameter changes

        // for each machine
        for (int x = 0; x < 16; x++) {
            // divide out the sends so we don't saturate the midi channel
            if (ticks == 0 && (x > 2)) {
                continue;
            } else if (ticks == 1 && (x > 5 || x < 3)) {
                continue;
            } else if (ticks == 2 && (x > 8 || x < 6)) {
                continue;
            } else if (ticks == 3 && (x > 11 || x < 9)) {
                continue;
            } else if (ticks == 4 && (x > 14 || x < 12)) {
                continue;
            } else if (ticks == 5 && (x > 16 || x < 15)) {
                continue;
            }
            // for each morph parameter
            for (int y = 0; y < 24; y++) {
                // if the machine morph and the param morph are on and we pass a random check, send
                // a random param change
                if (morph_machines[x] == 1) {
                    if (morph_params[y] == 1) {
                        if (generator.nextInt(this.speed) == 1) {
                            machine_drum.sendRandomParamChange(recv, x, y);
                        }
                    }
                }
            }
        }
        ticks++;
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#redrawMonome()
     */
    public void redrawMonome() {
        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 8; y++) {
                // redraw the morph machine state (top 2 rows)
                if (y < 2) {
                    int machine_num = getMachineNum(x, y);
                    if (morph_machines[machine_num] == 1) {
                        this.monome.led(x, y, 1, this.index);
                    } else {
                        this.monome.led(x, y, 0, this.index);
                    }
                    // redraw the morph param state (next 3 rows)
                } else if (y < 5) {
                    int param_num = getMachineNum(x, y - 2);
                    if (morph_params[param_num] == 1) {
                        this.monome.led(x, y, 1, this.index);
                    } else {
                        this.monome.led(x, y, 0, this.index);
                    }
                    // redraw the bottom row (auto morph and fx toggles)
                } else if (y == 7) {
                    if (x == 0) {
                        if (auto_morph == true) {
                            this.monome.led(x, y, 1, this.index);
                        } else {
                            this.monome.led(x, y, 0, this.index);
                        }
                    } else if (x > 0 && x < 5) {
                        this.monome.led(x, y, fx_morph[x - 1], this.index);
                    } else {
                        this.monome.led(x, y, 0, this.index);
                    }
                    // everything else should be off
                } else {
                    this.monome.led(x, y, 0, this.index);
                }
            }
        }
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#send(javax.sound.midi.MidiMessage, long)
     */
    public void send(MidiMessage message, long timeStamp) {
        if (this.recv == null) {
            return;
        }

        // pass midi clock messages on to the machinedrum for tempo sync
        ShortMessage shortMessage;
        if (message instanceof ShortMessage) {
            shortMessage = (ShortMessage) message;
            switch (shortMessage.getCommand()) {
            case 0xF0:
                // midi clock message
                if (shortMessage.getChannel() == 0x08) {
                    this.recv.send(message, timeStamp);
                }
                // midi start message
                if (shortMessage.getChannel() == 0x0A) {
                    this.recv.send(message, timeStamp);
                }
                // midi stop message
                if (shortMessage.getChannel() == 0x0C) {
                    this.recv.send(message, timeStamp);
                }
                break;
            default:
                this.recv.send(message, timeStamp);
                break;
            }
        }
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#toXml()
     */
    public String toXml() {
        String xml = "";
        xml += "      <name>Machine Drum Interface</name>\n";
        xml += "      <pageName>" + this.pageName + "</pageName>\n";
        xml += "      <selectedmidioutport>" + StringEscapeUtils.escapeXml(this.midiDeviceName)
                + "</selectedmidioutport>\n";
        xml += "      <speed>" + this.speed + "</speed>\n";
        return xml;
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#getPanel()
     */
    public JPanel getPanel() {
        if (this.panel != null) {
            return this.panel;
        }

        JPanel panel = new JPanel();
        AnchorLayout panelLayout = new AnchorLayout();
        panel.setLayout(panelLayout);
        panel.setPreferredSize(new java.awt.Dimension(319, 127));
        panel.add(getAddMidiOutButton(), new AnchorConstraint(775, 963, 917, 521, AnchorConstraint.ANCHOR_REL,
                AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL));
        panel.add(getUpdatePrefsButton(), new AnchorConstraint(767, 487, 917, 20, AnchorConstraint.ANCHOR_REL,
                AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL));
        panel.add(getSpeedTF(), new AnchorConstraint(507, 340, 712, 236, AnchorConstraint.ANCHOR_REL,
                AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL));
        panel.add(getSpeedLabel(), new AnchorConstraint(531, 236, 673, 57, AnchorConstraint.ANCHOR_REL,
                AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL));

        this.getUpdatePrefsButton().addActionListener(this);
        this.getAddMidiOutButton().addActionListener(this);

        pageNameLBL = new JLabel("Page " + (this.index + 1) + ": Machine Drum Interface");
        panel.add(pageNameLBL, new AnchorConstraint(0, 600, 120, 0, AnchorConstraint.ANCHOR_REL,
                AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL));

        JLabel midiout = new JLabel("MIDI Out: " + this.midiDeviceName);
        panel.add(midiout, new AnchorConstraint(271, 948, 429, 20, AnchorConstraint.ANCHOR_REL,
                AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL));
        pageNameLBL.setPreferredSize(new java.awt.Dimension(296, 20));

        this.panel = panel;
        return panel;
    }

    /**
     * @return The speed label
     */
    private JLabel getSpeedLabel() {
        if (speedLabel == null) {
            speedLabel = new JLabel();
            speedLabel.setText("Speed");
            speedLabel.setPreferredSize(new java.awt.Dimension(57, 18));
        }
        return speedLabel;
    }

    /**
     * @return The speed text field
     */
    private JTextField getSpeedTF() {
        if (speedTF == null) {
            speedTF = new JTextField();
            speedTF.setText("100");
            speedTF.setPreferredSize(new java.awt.Dimension(33, 26));
        }
        return speedTF;
    }

    /**
     * @return The Add MIDI Output button
     */
    private JButton getAddMidiOutButton() {
        if (addMidiOutButton == null) {
            addMidiOutButton = new JButton();
            addMidiOutButton.setText("Set MIDI Output");
            addMidiOutButton.setPreferredSize(new java.awt.Dimension(141, 18));
        }
        return addMidiOutButton;
    }

    /**
     * @return The Update Preferences button
     */
    private JButton getUpdatePrefsButton() {
        if (updatePrefsButton == null) {
            updatePrefsButton = new JButton();
            updatePrefsButton.setText("Update Preferences");
            updatePrefsButton.setPreferredSize(new java.awt.Dimension(149, 19));
        }
        return updatePrefsButton;
    }

    /**
     * @param speed Sets the speed to send random parameter changes or auto morph, lower is faster
     */
    public void setSpeed(int speed) {
        this.speed = speed;
        this.getSpeedTF().setText(String.valueOf(speed));
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#actionPerformed(java.awt.event.ActionEvent)
     */
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("Set MIDI Output")) {
            String[] midiOutOptions = this.monome.getMidiOutOptions();
            String deviceName = (String) JOptionPane.showInputDialog(this.monome, "Choose a MIDI Output to add",
                    "Set MIDI Output", JOptionPane.PLAIN_MESSAGE, null, midiOutOptions, "");

            if (deviceName == null) {
                return;
            }

            this.addMidiOutDevice(deviceName);
        }

        if (e.getActionCommand().equals("Update Preferences")) {
            this.speed = Integer.parseInt(this.getSpeedTF().getText());
        }
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#addMidiOutDevice(java.lang.String)
     */
    public void addMidiOutDevice(String deviceName) {
        this.recv = this.monome.getMidiReceiver(deviceName);
        this.midiDeviceName = deviceName;
        this.getAddMidiOutButton().removeActionListener(this);
        this.getUpdatePrefsButton().removeActionListener(this);
        this.panel.removeAll();
        this.panel = null;
        this.monome.redrawPanel();
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#getCacheDisabled()
     */
    public boolean getCacheDisabled() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.monome.pages.Page#destroyPage()
     */
    public void destroyPage() {
        return;
    }

    public void clearPanel() {
        this.panel = null;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public void handleADC(int adcNum, float value) {
        // TODO Auto-generated method stub

    }

    public void handleADC(float x, float y) {
        // TODO Auto-generated method stub

    }

    public boolean isTiltPage() {
        // TODO Auto-generated method stub
        return false;
    }

    public ADCOptions getAdcOptions() {
        // TODO Auto-generated method stub
        return null;
    }

    public void setAdcOptions(ADCOptions options) {
        // TODO Auto-generated method stub

    }

    public void configure(Element pageElement) {
        NodeList nameNL = pageElement.getElementsByTagName("pageName");
        Element el = (Element) nameNL.item(0);
        if (el != null) {
            NodeList nl = el.getChildNodes();
            String name = ((Node) nl.item(0)).getNodeValue();
            this.setName(name);
        }

        NodeList rowNL = pageElement.getElementsByTagName("speed");
        el = (Element) rowNL.item(0);
        if (el != null) {
            NodeList nl = el.getChildNodes();
            String speed = ((Node) nl.item(0)).getNodeValue();
            this.setSpeed(Integer.parseInt(speed));
        }
    }
}