]> ruin.nu Git - moosique.git/commitdiff
no message master origin
authorEinar Pehrson <einarp@itstud.chalmers.se>
Sun, 8 Jun 2003 20:23:52 +0000 (20:23 +0000)
committerEinar Pehrson <einarp@itstud.chalmers.se>
Sun, 8 Jun 2003 20:23:52 +0000 (20:23 +0000)
MooDialog.java
MooTrackView.java
MooViewCounter.java
Moosique.java
To Do.txt

index fc9c2c0b19bd39ad7c23a4560e06cac0513dcd0a..25e544adc383ea0cc67392bf33aa105a7d6319d3 100644 (file)
@@ -13,6 +13,9 @@ import java.beans.*;
  
 public class MooDialog extends JDialog {
 
+       private Container pane;
+       private Track[] tracks;
+
        private JLabel labelA, labelB, labelC, labelD, labelE, labelF, labelG, labelH;
        private JTextField textFieldA, textFieldB, textFieldC, textFieldD, textFieldE,
                           textFieldF, textFieldG, textFieldH, textFieldI, textFieldJ,
@@ -32,6 +35,7 @@ public class MooDialog extends JDialog {
                                TRANSPOSE = 11,
                                SCALE_VELOCITY = 12, 
                                RECORD = 13;
+       public static final String[] noteSizes = {"Whole", "Half", "Quarter", "Eighth", "Sixteenth"};
        
        /**
         * Constructor of the dialogs.
@@ -39,24 +43,25 @@ public class MooDialog extends JDialog {
         public MooDialog(int type) {
                super(Moosique.getGUI(), false);
                        
-               Container pane = getContentPane();
+               pane = getContentPane();
                pane.setLayout(null);
                
-               Track[] tracks = Moosique.getSequence().getTracks();
+               tracks = Moosique.getSequence().getTracks();
 
                switch (type) {
-                       case ADD_TRACK:         makeAddDialog(pane, tracks); break;
-                       case DELETE_TRACK:      makeDelDialog(pane, tracks); break;
-                       case COPY_TRACK:        makeCopyDialog(pane, tracks); break;
-                       case MOVE_TRACK:        makeMoveDialog(pane, tracks); break;
-                       case SET_POSITION:      makeSetPositionDialog(pane); break;
-                       case MANUAL:            makeTextDialog(pane, "Manual.txt"); break;
-                       case INSERT_MEASURE:    makeInsertMeasureDialog(pane); break;
-                       case DELETE_MEASURE:    makeDeleteMeasureDialog(pane); break;
-                       case SET_TEMPO:         makeSetTempoDialog(pane); break;
-                       case PREFERENCES:       makePrefsDialog(pane); break;
-                       case TRANSPOSE:         makeTransposeDialog(pane, tracks); break;
-                       case SCALE_VELOCITY:    makeScaleVelocityDialog(pane, tracks); break;
+                       case ADD_TRACK:         makeAddDialog(); break;
+                       case DELETE_TRACK:      makeDelDialog(); break;
+                       case COPY_TRACK:        makeCopyDialog(); break;
+                       case MOVE_TRACK:        makeMoveDialog(); break;
+                       case SET_POSITION:      makeSetPositionDialog(); break;
+                       case MANUAL:            makeTextDialog("User Manual", "Manual.txt", 30, 95); break;
+                       case INSERT_MEASURE:    makeInsertMeasureDialog(); break;
+                       case DELETE_MEASURE:    makeDeleteMeasureDialog(); break;
+                       case SET_TEMPO:         makeSetTempoDialog(); break;
+                       case PREFERENCES:       makePrefsDialog(); break;
+                       case TRANSPOSE:         makeTransposeDialog(); break;
+                       case SCALE_VELOCITY:    makeScaleVelocityDialog(); break;
+                       case RECORD:            makeRecordDialog(); break;
                }
         }
        
@@ -65,7 +70,7 @@ public class MooDialog extends JDialog {
         * @param pane          The container to put the dialog in.
         * @param tracks        A array containing miditracks.
         */
-       private void makeAddDialog(Container pane, Track[] tracks) {
+       private void makeAddDialog() {
                setTitle("Add track");
                // create the contents of the dialog and add to container
                labelA = new JLabel("Name of track", JLabel.CENTER);
@@ -77,7 +82,7 @@ public class MooDialog extends JDialog {
                pane.add(labelB);
                // list of where to add track
                trackListA = new JComboBox();
-               for (int i = 1; i <= tracks.length; i++) trackListA.addItem("Track " + i);
+               for (int i = 1; i < tracks.length; i++) trackListA.addItem("Track " + i);
                pane.add(trackListA);
                // ok and cancel button
                cancelButton = new JButton("Cancel");
@@ -103,7 +108,7 @@ public class MooDialog extends JDialog {
         * @param pane          The container to put the dialog in.
         * @param tracks        A array containing miditracks.
         */
-       private void makeDelDialog(Container pane, Track[] tracks) {
+       private void makeDelDialog() {
                setTitle("Delete track");
                // create the contents of the dialog and add to container
                labelB = new JLabel("Delete track", JLabel.CENTER);
@@ -134,7 +139,7 @@ public class MooDialog extends JDialog {
         * @param pane          The container to put the dialog in.
         * @param tracks        A array containing miditracks.
         */
-       private void makeCopyDialog(Container pane, Track[] tracks) {
+       private void makeCopyDialog() {
                setTitle("Copy Track");
                // create the contents of the dialog and add to container
                labelA = new JLabel("Track to copy", JLabel.CENTER);
@@ -172,7 +177,7 @@ public class MooDialog extends JDialog {
         * @param pane          The container to put the dialog in.
         * @param tracks        A array containing miditracks.
         */
-       private void makeMoveDialog(Container pane, Track[] tracks) {
+       private void makeMoveDialog() {
                setTitle("Move track");
                // create the contents of the dialog and add to container
                labelA = new JLabel("Track to move", JLabel.CENTER);
@@ -211,7 +216,7 @@ public class MooDialog extends JDialog {
         * @param pane          The container to put the dialog in.
         * @param tracks        A array containing miditracks.
         */
-       private void makeSetPositionDialog(Container pane) {
+       private void makeSetPositionDialog() {
                
                setTitle("Set edit position");
                // create the contents of the dialog and add to container
@@ -252,7 +257,7 @@ public class MooDialog extends JDialog {
         * Builds the insert measure popupdialog.
         * @param pane          The container to put the dialog in.
         */
-       private void makeInsertMeasureDialog(Container pane){
+       private void makeInsertMeasureDialog(){
                setTitle("Insert Measure");
                // create the contents of the dialog and add to container
                labelA = new JLabel("Insert at:", JLabel.RIGHT);
@@ -286,7 +291,7 @@ public class MooDialog extends JDialog {
         * Builds the delete measure popupdialog.
         * @param pane          The container to put the dialog in.
         */
-       private void makeDeleteMeasureDialog(Container pane) {
+       private void makeDeleteMeasureDialog() {
                setTitle("Delete Measure");
                // create the contents of the dialog and add to container
                labelA = new JLabel("Delete at:", JLabel.RIGHT);
@@ -320,7 +325,7 @@ public class MooDialog extends JDialog {
         * Builds the set tempo dialog.
         * @param pane          The container to put the dialog in.
         */
-       private void makeSetTempoDialog(Container pane) {
+       private void makeSetTempoDialog() {
                setTitle("Set tempo");
                // create contents of dialog and add to container
                // track edit-intervall labels
@@ -429,7 +434,7 @@ public class MooDialog extends JDialog {
         * @param pane          The container to put the dialog in.
         * @param tracks        A array containing miditracks.
         */
-       private void makeTransposeDialog(Container pane, Track[] tracks) {
+       private void makeTransposeDialog() {
                setTitle("Transpose");
                // create contents of dialog and add to container
                // track edit-intervall labels
@@ -535,7 +540,7 @@ public class MooDialog extends JDialog {
         * @param pane  The container to put the dialog in.
         * @param tracks        A array containing miditracks.
         */
-       private void makeScaleVelocityDialog(Container pane, Track[] tracks) {
+       private void makeScaleVelocityDialog() {
                setTitle("Scale velocity");
                // create contents of dialog and add to container
                // track edit-intervall labels
@@ -651,8 +656,8 @@ public class MooDialog extends JDialog {
        }
        /** creates the "User manual dialog" that displays a  textfile
        */
-       private void makeTextDialog(Container pane, String filename) {
-               setTitle("User Manual");
+       private void makeTextDialog(String title, String filename, int rows, int columns) {
+               setTitle(title);
                pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
                File manual = new File(filename);
                String s;
@@ -662,9 +667,9 @@ public class MooDialog extends JDialog {
                        br.read(chars, 0, (int)manual.length());
                        s = new String(chars);
                } catch (Exception ex) {
-                       s = "Manual not found";
+                       s = "File not found";
                }
-               JTextArea text = new JTextArea(s, 30, 95);
+               JTextArea text = new JTextArea(s, rows, columns);
                text.setLineWrap(true);
                text.setWrapStyleWord(true);
                text.setEnabled(false);
@@ -683,7 +688,7 @@ public class MooDialog extends JDialog {
                setVisible(true);
        }
 
-       private void makePrefsDialog(Container pane) {
+       private void makePrefsDialog() {
                /*              
                MidiDevice.Info[] devInfo = MidiSystem.getMidiDeviceInfo();
                for (int i = 0; i < devInfo.length; i++) {
@@ -702,19 +707,88 @@ public class MooDialog extends JDialog {
                */
        }
 
-       private void makeRecordDialog(Container pane) {
-       /*      Show a dialog with:
-               "Track" combo box,
-               "Channel" field? (disabled?,
-               "Quantize" pane with
-                       "Quantize" checkbox,
-                       "Resolution" combo box,
-                       "Location" checkboxes and
-                       "Duration" checkboxes
-               "Start Recording" button.
-               
-               Moosique.record(track);
-               */
+       private void makeRecordDialog() {
+               setTitle("Record");
+
+               JPanel panel = new JPanel();
+               panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+
+               // Creating track combo box,
+               panel.add(new Label("Track: "));
+               trackListA = new JComboBox();
+               for (int i = 1; i < tracks.length; i++) trackListA.addItem("Track " + i);
+               trackListA.setFont(Moosique.getGUI().FONT);
+               panel.add(trackListA);
+
+               // Creating channel combo box
+               panel.add(new Label("Channel: "));
+               JComboBox channelList = new JComboBox();
+               for (int i = 1; i <= 16; i++) channelList.addItem("Channel " + i);
+               channelList.setFont(Moosique.getGUI().FONT);
+               panel.add(channelList);
+
+               // Creating quantize pane
+               JLayeredPane quantizePane = new JLayeredPane();
+               quantizePane.setBorder(BorderFactory.createTitledBorder("Quantize"));
+               JCheckBox quantizeBox = new JCheckBox("Quantize");
+               quantizePane.add(quantizeBox);
+               JLabel quantizeSizeLabel = new JLabel("Resolution");
+               JComboBox quantizeSize = new JComboBox(noteSizes);
+               quantizeSize.setSelectedIndex(4);
+               quantizeSize.setEnabled(false);
+               quantizeSize.setFont(Moosique.getGUI().FONT);
+               quantizeSizeLabel.setLabelFor(quantizeSize);
+               quantizePane.add(quantizeSizeLabel);
+               quantizePane.add(quantizeSize);
+               JCheckBox quantizeLocationBox = new JCheckBox("Affect location", true);
+               quantizeLocationBox.setEnabled(false);
+               quantizePane.add(quantizeLocationBox);
+               JCheckBox quantizeDurationBox = new JCheckBox("Affect duration", true);
+               quantizeDurationBox.setEnabled(false);
+               quantizePane.add(quantizeDurationBox);
+               panel.add(quantizePane);
+
+               // Creating buttons
+               final String btnString1 = "Record!";
+               final String btnString2 = "Cancel";
+               Object[] options = {btnString1, btnString2};
+
+               // Creating option pane
+               optionPane = new JOptionPane(panel, 
+                                           JOptionPane.QUESTION_MESSAGE,
+                                           JOptionPane.YES_NO_OPTION,
+                                           null,
+                                           options,
+                                           options[0]);
+               optionPane.addPropertyChangeListener(new PropertyChangeListener() {
+                   public void propertyChange(PropertyChangeEvent e) {
+                       String prop = e.getPropertyName();
+       
+                       if (isVisible() && (e.getSource() == optionPane) &&
+                       (prop.equals(JOptionPane.VALUE_PROPERTY) || prop.equals(JOptionPane.INPUT_VALUE_PROPERTY))) {
+                               Object value = optionPane.getValue();
+                               if (value == JOptionPane.UNINITIALIZED_VALUE) return;
+                               optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
+                               
+                               if (value.equals(btnString1)) {
+                                       // boolean[] quantizers = {quantize, location, duration};
+                                       Track track = tracks[trackListA.getSelectedIndex() + 1];
+                                       int channel = Moosique.getGUI().getView().getTrackView(track).getTitle().getChannel();
+                                       boolean[] quantizers = {false, false, false};
+                                       int resolution = Moosique.SIXTEENTH_NOTE;
+                                       Moosique.record(track, channel, quantizers, resolution);
+                               }
+                               setVisible(false);
+                       }
+                   }
+               });
+               setContentPane(optionPane);
+               setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+
+               setResizable(false);
+               pack();
+               setLocationRelativeTo(Moosique.getGUI());
+               setVisible(true);
        }
 
        private MooNote note;
@@ -729,9 +803,12 @@ public class MooDialog extends JDialog {
         */
        public MooDialog(MooNote mn) {
                super(Moosique.getGUI(), "Note properties", true);
+
+               note = mn;
+
                JPanel panel = new JPanel();
                panel.setLayout(new GridLayout(3,2));
-               note = mn;
+
                pitch = new JTextField(new Integer(note.getPitch()).toString(),3);
                panel.add(new Label("Pitch: "));
                panel.add(pitch);
@@ -812,6 +889,7 @@ public class MooDialog extends JDialog {
                    }
                });
                pack();
+               setLocationRelativeTo(Moosique.getGUI());
                setVisible(true);
        }
 }
index 1c7abe4a979bab0b6294131b4b556f132ef3508e..c284e7df5acc9e4ce2a2407f67f373e5fdf548aa 100644 (file)
@@ -21,7 +21,7 @@ public class MooTrackView extends JPanel {
        private JMenu popupAdd, selPopupTranspUp, selPopupTranspDown;
        private JMenuItem popupAddItemsCustom, popupAddItemsLast, popupPaste;
        private JMenuItem popupAddItemsWhole, popupAddItemsHalf, popupAddItemsQuarter, popupAddItemsEighth, popupAddItemsSixteenth;
-       private JMenuItem selPopupCopy, selPopupCut, selPopupRemove;
+       private JMenuItem selPopupProps, selPopupCopy, selPopupCut, selPopupRemove;
        private JMenuItem[] selPopupTranspUpItems, selPopupTranspDownItems;
 
        private ArrayList coords; 
@@ -89,6 +89,7 @@ public class MooTrackView extends JPanel {
 
                // Creates selection pop-up menu.
                selPopup = new JPopupMenu();
+               selPopupProps = addMenuItem(selPopup, "Properties...");
                selPopupCopy = addMenuItem(selPopup, "Copy selection");
                selPopupCut = addMenuItem(selPopup, "Cut selection");
                selPopupRemove = addMenuItem(selPopup, "Remove selection");
@@ -389,6 +390,8 @@ public class MooTrackView extends JPanel {
         * @param y     the y-coordinate in which to display the menu
         */
        public void showSelectionPopup(Component c, int x, int y) {
+               // Determines whether the "Properties" item should be available.
+               selPopupProps.setEnabled(Moosique.getSelection().size() == 1);
                selPopup.show(c, x, y);
        }
 
@@ -490,6 +493,8 @@ public class MooTrackView extends JPanel {
                        } else if (source == popupPaste) {
                                pasteCopiedNotes();
                        // Handling selection popup actions.
+                       } else if (source == selPopupProps) {
+                               new MooDialog(((MooNoteElement)Moosique.getSelection().first()).getNote());
                        } else if (source == selPopupCopy) {
                                copySelectedNotes();
                        } else if (source == selPopupCut) {
index 16d34b9c42b9abdb3f7767e73683af5c268faad4..de1dac2db6e25c53bde2e2ded1d9c49791d24c60 100644 (file)
@@ -17,34 +17,36 @@ public class MooViewCounter extends JPanel {
        /** 
         * Creates an musical ruler depending on the timesignature
         */
-
        public MooViewCounter (MetaMessage[] timeSigs) {
-               int timeSig1 = 4, timeSig2 = 4; // ...for now
+               // ...for now
+               int timeSig1 = 4, timeSig2 = 4;
+               calculateLineSpecs(timeSig1, timeSig2);
                setBackground(Moosique.getGUI().bgColor);
                setPreferredSize(new Dimension(35, 200 * CELL_HEIGHT));
+       }
 
-               switch (timeSig2) {
-                       case  16: measure = timeSig1;           // 1/16
-                               break;
-                       case  8: measure = timeSig1 * 2;        // 1/16
-                                halfBeat = measure / timeSig1; // 1/8
-                               break;
-                       case  4: measure = timeSig1 * 4;        // 1/16
-                                halfBeat = beat / 2;           // 1/8          
-                                beat = measure / timeSig1;     // 1/4  
-                               break;
-                       case  2: measure = timeSig1 * 8;        // 1/16
+       private void calculateLineSpecs(int ts1, int ts2) {
+               switch (ts2) {
+                       case 16: measure = ts1;                 // 1/16
+                                break;
+                       case  8: measure = ts1 * 2;     // 1/16
+                                halfBeat = measure / ts1;      // 1/8
+                                break;
+                       case  2: measure = ts1 * 8;     // 1/16
                                 halfBeat = beat / 2;           // 1/8
                                 beat = halfNote / 2;           // 1/4
-                                halfNote = measure / timeSig1; // 1/2
-                               break;
-                       case  1: measure = timeSig1 * 16;       // 1/16
+                                halfNote = measure / ts1;      // 1/2
+                                break;
+                       case  1: measure = ts1 * 16;    // 1/16
                                 halfBeat = beat / 2;           // 1/8
                                 beat = halfNote / 2;           // 1/4
                                 halfNote = measure / 2;        // 1/2
-                               break;
+                                break;
+                       default: measure = ts1 * 4;     // 1/16
+                                halfBeat = beat / 2;           // 1/8          
+                                beat = measure / ts1;  // 1/4  
+                                break;
                }
-               
        }
 
        /**
@@ -56,6 +58,20 @@ public class MooViewCounter extends JPanel {
                if (!(g instanceof Graphics2D)) return;
                Graphics2D g2 = (Graphics2D)g;
                g2.setColor(Color.black);
+
+
+               /* Using time signature...
+               for (int i = 0, tick = getTicksForPosition(i, 0, 0); tick < Moosique.getSequence().getTickLength(); i++) {
+                       int[] ts = getTimeSig(tick);
+                       calculateLineSpecs(ts[0], ts[1]);
+                       g2.drawLine(0, c * CELL_HEIGHT, 5, c * CELL_HEIGHT);                                    // 1/16
+                       g2.drawLine(0, c * CELL_HEIGHT * halfBeat, 10, c * CELL_HEIGHT * halfBeat);             // 1/8
+                       g2.drawLine(0, c * CELL_HEIGHT * beat, 15, c * CELL_HEIGHT * beat);                     // 1/4
+                       g2.drawLine(0, c * CELL_HEIGHT * halfNote, 20, c * CELL_HEIGHT * halfNote);             // 1/2
+                       g2.drawLine(0, c * CELL_HEIGHT * measure, 30, c * CELL_HEIGHT * measure);               // 1/1
+               }
+               */
+
                for (int c = 0; c < 200; c++) {
                        g2.drawLine(0, c * CELL_HEIGHT, 5, c * CELL_HEIGHT);                                    // 1/16
                        g2.drawLine(0, c * CELL_HEIGHT * halfBeat, 10, c * CELL_HEIGHT * halfBeat);             // 1/8
index 68bfd1799fd4ed00e07d1e2cc6e9aa891a3b285d..160380d5bb88be74d642efcc222d9d4cad88b411 100644 (file)
@@ -13,6 +13,7 @@ import java.util.*;
  
 public class Moosique {
 
+       // GUI and MIDI device variables
        private static MooGUI gui;
        private static Sequence seq;
        private static Sequencer sequencer;
@@ -20,18 +21,28 @@ public class Moosique {
        private static Receiver receiver;
        private static MidiChannel[] channels;
        private static MidiChannel activeChannel;
+
+       // Recording variables
        private static Track recordTrack = null;
        private static MooTrackView recordTrackView = null;
+       private static boolean[] quantizers = {false, false, false};
+       private static int quantizeResolution;
 
+       // Collections
        private static ArrayList copyBuffer, emptyTracks, timeSignatures, tempoChanges;
        private static TreeSet selection;
        private static Map trackMute = new HashMap();
        private static Map trackSolo = new HashMap();
-       private static Thread player;
 
+       // Various...
        private static File file = null;
        private static long editPosition;
+       private static Thread player;
+
+       // Preferences
        private static boolean makeGUI = true, initSound = true, edited = false, drawEmptyTracks = false;
+
+       // Constants
        public static final int DEFAULT_RESOLUTION = 96, DEFAULT_TRACKS = 4;
        public static final int WHOLE_NOTE = 16, HALF_NOTE = 8, QUARTER_NOTE = 4, EIGHTH_NOTE = 2, SIXTEENTH_NOTE = 1;
 
@@ -284,22 +295,6 @@ public class Moosique {
                editPosition = ticks;
        }
 
-       /** 
-        * Sets the current editing position of the sequencer.
-        * @param ticks         the tick position
-        */
-       public static void setTempo(int bpm) {
-               // tempoMsg
-       }
-
-       /** 
-        * Sets the current editing position of the sequencer.
-        * @param ticks         the tick position
-        */
-       public static void setTimeSig(int bpm) {
-               // timeSigMsg
-       }
-       
        /** 
         * Sets the solo setting of the given track.
         * @param on    true for solo, false for not
@@ -475,26 +470,34 @@ public class Moosique {
                        recordTrackView.disableKeyboardRecording();
                        sequencer.stopRecording();
                        sequencer.recordDisable(recordTrack);
-//                     if (quantize) recordTrackView.placeNewNotes(quantize(
-//                             convertTrack(recordTrack), SIXTEENTH_NOTE, true, true));
-//                     else recordTrackView.placeNewNotes(Moosique.convertTrack(recordTrack));
+                       if (quantizers[0]) recordTrackView.placeNewNotes(quantize(
+                               convertTrack(recordTrack), quantizeResolution, quantizers[1], quantizers[2]));
+                       else recordTrackView.placeNewNotes(Moosique.convertTrack(recordTrack));
                }
        }
 
        /** 
         * Enables recording to the given track.
+        * @param track         the track in which to store the recorded data
+        * @param tempo         the channel from which to record data
+        * @param quantizers    an array of booleans where 0 = quantize?, 1 = location, 2 = duration
+        * @param resolution    the note size to round each note to
+        * @return if the recording was initialised successfully
         */
-       public static boolean record(Track track) {
-/*             try {
+       public static boolean record(Track track, int channel, boolean[] quants, int resolution) {
+               try {
                        sequencer.recordEnable(track, channel);
                        sequencer.startRecording();
                } catch(Exception e) {
+                       e.printStackTrace();
                        return false;
                }
+               quantizers = quants;
+               quantizeResolution = resolution;
+               recordTrack = track;
                recordTrackView = gui.getView().getTrackView(track);
                recordTrackView.enableKeyboardRecording();
                Moosique.setEdited(); 
-*/
                return true;
        }
 
@@ -557,6 +560,36 @@ public class Moosique {
                return decodeTempo(((MetaMessage)tempoEvent.getMessage()).getData());
        }
 
+       /** 
+        * Sets the tempo at the given tick position.
+        * @param ticks         the tick position
+        */
+       public static void setTempo(long tick, int bpm) {
+               // Checks for a tempo event at the given tick position. 
+               MidiEvent tempoEvent = null;
+               Iterator it = tempoChanges.iterator();
+               while(it.hasNext()) {
+                       MidiEvent nextTempoEvent = (MidiEvent)it.next();
+                       if (nextTempoEvent.getTick() == tick) {
+                               tempoEvent = nextTempoEvent;
+                               break;
+                       }
+               }
+
+               // If none was found, creates and adds a new one.
+               if (tempoEvent == null) {
+                       tempoEvent = new MidiEvent(new MetaMessage(), tick);
+                       (seq.getTracks())[0].add(tempoEvent);
+                       tempoChanges.add(tempoEvent);
+                       Collections.sort(tempoChanges, new MidiEventComparator());
+               }
+
+               // Sets the tempo of the event (found or created).
+               try {
+                       ((MetaMessage)tempoEvent.getMessage()).setMessage(81, encodeTempo(bpm), 3);
+               } catch (InvalidMidiDataException e) {}
+       }
+
        /** 
         * Returns the byte array for the given time signature.
         * @param numerator     the numerator of the time signature
@@ -597,13 +630,43 @@ public class Moosique {
                if (timeSignatures.size() > 1) {
                        for (int i = 1; i < timeSignatures.size(); i++) {
                                MidiEvent nextTimeSigEvent = (MidiEvent)timeSignatures.get(i);
-                               if (nextTimeSigEvent.getTick() < tick && nextTimeSigEvent.getTick() > timeSigEvent.getTick())
+                               if (nextTimeSigEvent.getTick() <= tick && nextTimeSigEvent.getTick() > timeSigEvent.getTick())
                                        timeSigEvent = nextTimeSigEvent;
                        }
                }
                return decodeTimeSig(((MetaMessage)timeSigEvent.getMessage()).getData());
        }
 
+       /** 
+        * Sets the time signature at the given tick position.
+        * @param ticks         the tick position
+        */
+       public static void setTimeSig(long tick, int numerator, int denominator) {
+               // Checks for a time signature event at the given tick position. 
+               MidiEvent timeSigEvent = null;
+               Iterator it = timeSignatures.iterator();
+               while(it.hasNext()) {
+                       MidiEvent nextTimeSigEvent = (MidiEvent)it.next();
+                       if (nextTimeSigEvent.getTick() == tick) {
+                               timeSigEvent = nextTimeSigEvent;
+                               break;
+                       }
+               }
+
+               // If none was found, creates and adds a new one.
+               if (timeSigEvent == null) {
+                       timeSigEvent = new MidiEvent(new MetaMessage(), tick);
+                       (seq.getTracks())[0].add(timeSigEvent);
+                       timeSignatures.add(timeSigEvent);
+                       Collections.sort(timeSignatures, new MidiEventComparator());
+               }
+
+               // Sets the time signature of the event (found or created).
+               try {
+                       ((MetaMessage)timeSigEvent.getMessage()).setMessage(88, encodeTimeSig(numerator, denominator), 4);
+               } catch (InvalidMidiDataException e) {}
+       }
+       
        /**
         * Calculates the position (measures, beats, ticks) in the current sequence for the given tick position.
         * @param tickPosition the tick position for which to calculate the position
@@ -709,20 +772,18 @@ public class Moosique {
         * Replaces the current sequence with a new one, holding three empty tracks.
         */
        public static void clearSequence() {
+               // Reinitializes sequence variables
+               file = null;
+               reinitializeLists();
+
                try {
                        // Creates a new sequence.
                        seq = new Sequence(Sequence.PPQ, DEFAULT_RESOLUTION, DEFAULT_TRACKS);
                        Track[] tracks = seq.getTracks();
 
-                       // Creates messages for default tempo (120) and time signature (4/4), and adds them to track 0.
-                       MetaMessage timeSigMsg = new MetaMessage();
-                       MetaMessage tempoMsg = new MetaMessage();
-                       try {
-                               timeSigMsg.setMessage(88, encodeTimeSig(4, 4), 4);
-                               tempoMsg.setMessage(81, encodeTempo(120), 3);
-                       } catch (InvalidMidiDataException e) {}
-                       tracks[0].add(new MidiEvent(timeSigMsg, (long)0));
-                       tracks[0].add(new MidiEvent(tempoMsg, (long)0));
+                       // Sets default tempo (120) and time signature (4/4) at the beginning of the sequence.
+                       setTempo(0, 120);
+                       setTimeSig(0, 4, 4);
 
                        // Sets program and title for the tracks.
                        initializeTrack(tracks[1], 0, 24, "Guitar");
@@ -730,10 +791,6 @@ public class Moosique {
                        initializeTrack(tracks[3], 9, 0, "Drums");
                } catch (InvalidMidiDataException e) {}
 
-               // Reinitializes sequence variables
-               file = null;
-               reinitializeLists();
-
                // Sends the sequence to the GUI.
                if (gui != null) gui.setSequence(seq, null);
        }
index a2b54a20cee18245e3909fcba8a92e08295ac598..aa1b619451e98282d30b9d64c7b190af51e3322f 100644 (file)
--- a/To Do.txt
+++ b/To Do.txt
@@ -2,7 +2,7 @@
 \f
 AKTIVITET
 Björn  Menyn, dialogerna
-Einar  Inspelning
+Einar  Inspelning, MooViewCounter
 Mike   
 Rolle  Spara konfiguration
                Arbetskatalog
@@ -17,11 +17,6 @@ x Varf
 x Varför hänger sig Play när man spelar in eller ändrar längd på en not?
 x Kopiera/flytta spår, möjligt?
 
-\f
-ANNAT
-x Fixa InstrumentList.
-x Textfält som gör att man bara kan skriva in siffror? (MooNoteProp)
-
 \f
 PREFERENCES
 
@@ -34,10 +29,7 @@ Vilka mer booleaner ska man kunna 
 \f
 SWING
        MooDialog
-               Fixa en Record-dialog.
-
-       MooView
-               Lägg till en tom panel för att fylla ut skärmen. Med BoxLayout?
+               Textfält som gör att man bara kan skriva in siffror? (NoteProp)
 
        MooMenu
                Mnemonicsarna är konstiga.
@@ -57,6 +49,9 @@ SWING
                        (Omöjligt att följa strecken till högra änden av skärmen.)
                Highlighta noter som spelas? (Enligt kravspec.)
 
+       MooView
+               Lägg till en tom panel för att fylla ut skärmen. Med BoxLayout?
+
 \f
 jar cmf manif Moosique.jar *.class *.java midi\*.mid images\*.gif Manual.txt
 manif: Main-Class: Moosique