From 278cdee04a1413adc98d137837b0f5303da7f7b2 Mon Sep 17 00:00:00 2001 From: pfrison Date: Sun, 17 Mar 2019 02:39:00 +0100 Subject: [PATCH] VRGNYMusicLights timeline beginning --- VRGNYMusicLights/Sources/AnimationPlayer.java | 35 +++++++++++++++++------------------ VRGNYMusicLights/Sources/Interface.java | 51 +++++++++++++++++++-------------------------------- VRGNYMusicLights/Sources/InvalidPatternException.java | 2 +- VRGNYMusicLights/Sources/Main.java | 10 ++++++++-- VRGNYMusicLights/Sources/Music.java | 2 ++ VRGNYMusicLights/Sources/MusicList.java | 1 + VRGNYMusicLights/Sources/MusicPath.java | 40 ++++++++++++++++++++-------------------- VRGNYMusicLights/Sources/MusicPattern.java | 27 +++++++++++++++++++-------- VRGNYMusicLights/Sources/MusicRenderer.java | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ VRGNYMusicLights/Sources/PatternJPanel.java | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VRGNYMusicLights/Sources/PlayJPanel.java | 32 ++++++++++++++++++++++++++++++++ VRGNYMusicLights/Sources/TimeLineJList.java | 36 ++++++++++++++++++++++++++++++++++++ VRGNYMusicLights/Sources/TimeLineJPanel.java | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VRGNYMusicLights/Sources/Util.java | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 14 files changed, 464 insertions(+), 81 deletions(-) create mode 100644 VRGNYMusicLights/Sources/MusicRenderer.java create mode 100644 VRGNYMusicLights/Sources/PatternJPanel.java create mode 100644 VRGNYMusicLights/Sources/PlayJPanel.java create mode 100644 VRGNYMusicLights/Sources/TimeLineJList.java create mode 100644 VRGNYMusicLights/Sources/TimeLineJPanel.java create mode 100644 VRGNYMusicLights/Sources/Util.java diff --git a/VRGNYMusicLights/Sources/AnimationPlayer.java b/VRGNYMusicLights/Sources/AnimationPlayer.java index 6569fce..3356186 100644 --- a/VRGNYMusicLights/Sources/AnimationPlayer.java +++ b/VRGNYMusicLights/Sources/AnimationPlayer.java @@ -10,8 +10,7 @@ import javax.swing.JPanel; public class AnimationPlayer extends JPanel implements ActionListener { private static final long serialVersionUID = 1L; - private LightCanvasJPanel lightCanvas; - private MusicList musicList; + private Interface interf; private JButton backward; private JButton stop; @@ -19,10 +18,9 @@ public class AnimationPlayer extends JPanel implements ActionListener { private JButton pause; private JButton forward; - private long tick = 0; private boolean go = false; private boolean stopClock = false; - private static final int TICK_JUMP = 20; + private static final int TICK_JUMP = 10; private Thread tickClock = new Thread(new Runnable() { @Override public void run() { @@ -34,25 +32,24 @@ public class AnimationPlayer extends JPanel implements ActionListener { } long before = System.currentTimeMillis(); - lightCanvas.paintLights(musicList.render(tick)); - tick += TICK_JUMP; + interf.computeTick(); + interf.tick += TICK_JUMP; long after = System.currentTimeMillis(); if(after - before < TICK_JUMP) { - try { Thread.sleep(10 - after + before);} + try { Thread.sleep(TICK_JUMP - after + before);} catch (InterruptedException ignored) {} } else if(after - before > TICK_JUMP) { - System.err.println("Animation were slowed down by " + String.valueOf(after - before - 10) + " ticks !"); + System.err.println("Animation were slowed down by " + String.valueOf(after - before - TICK_JUMP) + " ticks !"); } } } }); public void stopTickClock() {stopClock = true;} - public AnimationPlayer(LightCanvasJPanel lightCanvas, MusicList musicList) { this(lightCanvas, musicList, BoxLayout.LINE_AXIS); } - public AnimationPlayer(LightCanvasJPanel lightCanvas, MusicList musicList, int direction) { - this.lightCanvas = lightCanvas; - this.musicList = musicList; + public AnimationPlayer(Interface interf) { this(interf, BoxLayout.LINE_AXIS); } + public AnimationPlayer(Interface interf, int direction) { + this.interf = interf; setLayout(new BoxLayout(this, direction)); @@ -90,20 +87,22 @@ public class AnimationPlayer extends JPanel implements ActionListener { @Override public void actionPerformed(ActionEvent e) { - // TODO player actions if(e.getSource() == backward) { - tick -= 500; - if(tick < 0) - tick = 0; + interf.tick -= 100; + if(interf.tick < 0) + interf.tick = 0; + interf.computeTick(); }else if(e.getSource() == stop) { go = false; - tick = 0; + interf.tick = 0; + interf.computeTick(); }else if(e.getSource() == play) { go = true; }else if(e.getSource() == pause) { go = false; }else if(e.getSource() == forward) { - tick += 500; + interf.tick += 100; + interf.computeTick(); } } } diff --git a/VRGNYMusicLights/Sources/Interface.java b/VRGNYMusicLights/Sources/Interface.java index faafb37..d3320b5 100644 --- a/VRGNYMusicLights/Sources/Interface.java +++ b/VRGNYMusicLights/Sources/Interface.java @@ -1,19 +1,21 @@ import java.awt.BorderLayout; -import java.awt.Font; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; -import javax.swing.JLabel; import javax.swing.JPanel; public class Interface extends JFrame{ private static final long serialVersionUID = 1L; - private static final Font titleFont = new Font(new JLabel().getFont().getName(), Font.BOLD, 14); - private static final Font defaultFont = new Font(new JLabel().getFont().getName(), Font.PLAIN, new JLabel().getFont().getSize()); + //private static final Font titleFont = new Font(new JLabel().getFont().getName(), Font.BOLD, 14); + //private static final Font defaultFont = new Font(new JLabel().getFont().getName(), Font.PLAIN, new JLabel().getFont().getSize()); - private MusicList musicList; - private AnimationPlayer animPlayer; + protected MusicList musicList; + protected AnimationPlayer animPlayer; + protected TimeLineJPanel timeLinePanel; + protected TimeLineJList timeLineList; + protected LightCanvasJPanel lightCanvas; + protected long tick = 0; public Interface(MusicList musicList, final Runnable executeOnClose) { super("VRGNYMusicLights"); @@ -22,6 +24,7 @@ public class Interface extends JFrame{ populateWindow(); pack(); setLocationRelativeTo(null); // center window + getContentPane().requestFocus(); addWindowListener(new WindowAdapter() { @Override @@ -35,34 +38,18 @@ public class Interface extends JFrame{ }); } + protected void computeTick() { + lightCanvas.paintLights(musicList.render(tick)); + timeLineList.repaint(); + timeLinePanel.updateTick(); + } + private void populateWindow() { JPanel mainPanel = new JPanel(new BorderLayout()); - addPlayPanel(mainPanel); - addTimeLine(mainPanel); + timeLinePanel = new TimeLineJPanel(this, musicList); + mainPanel.add(timeLinePanel, BorderLayout.CENTER); + lightCanvas = new LightCanvasJPanel(); + mainPanel.add(new PlayJPanel(this, lightCanvas), BorderLayout.SOUTH); add(mainPanel); } - - private void addPlayPanel(JPanel parent) { - JPanel playPanel = new JPanel(new BorderLayout()); - - // title - JLabel title = new JLabel("Visualizer :"); - title.setFont(titleFont); - playPanel.add(title, BorderLayout.NORTH); - - // lights - LightCanvasJPanel lightCanvas = new LightCanvasJPanel(); - playPanel.add(lightCanvas, BorderLayout.CENTER); - - // controls - animPlayer = new AnimationPlayer(lightCanvas, musicList); - animPlayer.setAlignmentX(CENTER_ALIGNMENT); - playPanel.add(animPlayer, BorderLayout.SOUTH); - - parent.add(playPanel, BorderLayout.SOUTH); - } - - private void addTimeLine(JPanel parent) { - JPanel timeLine = new JPanel(); - } } diff --git a/VRGNYMusicLights/Sources/InvalidPatternException.java b/VRGNYMusicLights/Sources/InvalidPatternException.java index 2aaaaf1..9668ca1 100644 --- a/VRGNYMusicLights/Sources/InvalidPatternException.java +++ b/VRGNYMusicLights/Sources/InvalidPatternException.java @@ -3,6 +3,6 @@ public class InvalidPatternException extends RuntimeException { private static final long serialVersionUID = 1L; public InvalidPatternException() { - super("Invalid pattern given. Length must be equal to 4."); + super("Invalid pattern given. Length must be equal to 5."); } } diff --git a/VRGNYMusicLights/Sources/Main.java b/VRGNYMusicLights/Sources/Main.java index 8aa18b3..6436043 100644 --- a/VRGNYMusicLights/Sources/Main.java +++ b/VRGNYMusicLights/Sources/Main.java @@ -2,6 +2,7 @@ import javax.swing.JOptionPane; /* TODO list : * - keyboard listener for animation player (play / pause = space, forward = semicolon, backward = comma, stop = backspace) + * - pattern timeline info to follow scroll horizontal ? */ public class Main { public static void main(String[] args) throws InterruptedException { @@ -22,8 +23,13 @@ public class Main { MusicList musicList = new MusicList(null); musicList.addMusic( new Music( - new MusicPattern(new int[] {1000, 0, 0, 1000}, 1000, 0), - new MusicPath(MusicPath.CENTER_IN, 1000), + new MusicPattern(new int[] {0, 10, 100, 10, 100}, 100, 1000), + new MusicPath(MusicPath.CENTER_OUT, 1000), + 1)); + musicList.addMusic( + new Music( + new MusicPattern(new int[] {0, 10, 100, 10, 100}, 1, 0), + new MusicPath(MusicPath.CENTER_OUT, 1000), 1)); Interface i = new Interface(musicList, new Runnable() { diff --git a/VRGNYMusicLights/Sources/Music.java b/VRGNYMusicLights/Sources/Music.java index 980e255..67d7b84 100644 --- a/VRGNYMusicLights/Sources/Music.java +++ b/VRGNYMusicLights/Sources/Music.java @@ -10,6 +10,8 @@ public class Music { this.volume = volume; } + public MusicPattern getMusicPattern() { return pattern; } + public double[] render(long tick) { double[] lights = new double[lightTickDelais.length]; for(int i=0; i(); } + public ArrayList getList() { return musics; } public void addMusic(Music music) { musics.add(music); } public void deleteMusic(int index) { musics.remove(index); } diff --git a/VRGNYMusicLights/Sources/MusicPath.java b/VRGNYMusicLights/Sources/MusicPath.java index 4e2e3d1..6c1c903 100644 --- a/VRGNYMusicLights/Sources/MusicPath.java +++ b/VRGNYMusicLights/Sources/MusicPath.java @@ -75,34 +75,34 @@ public class MusicPath { || animation == CENTER_IN) { switch (animation) { case VERTICAL_DOWN: - ticksDelais[i] += tickLateVerticalDown(LIGHT_COORDS[i][1]); + ticksDelais[i] -= tickLateVerticalDown(LIGHT_COORDS[i][1]); break; case VERTICAL_UP: - ticksDelais[i] += tickLateVerticalUp(LIGHT_COORDS[i][1]); + ticksDelais[i] -= tickLateVerticalUp(LIGHT_COORDS[i][1]); break; case HORIZONTAL_TO_LEFT: - ticksDelais[i] += tickLateHorizontalToLeft(LIGHT_COORDS[i][0]); + ticksDelais[i] -= tickLateHorizontalToLeft(LIGHT_COORDS[i][0]); break; case HORIZONTAL_TO_RIGHT: - ticksDelais[i] += tickLateHorizontalToRight(LIGHT_COORDS[i][0]); + ticksDelais[i] -= tickLateHorizontalToRight(LIGHT_COORDS[i][0]); break; case DIAGONAL_TOP_RIGHT_DOWN_LEFT: - ticksDelais[i] += tickLateDiagTRDL(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); + ticksDelais[i] -= tickLateDiagTRDL(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); break; case DIAGONAL_DOWN_LEFT_TOP_RIGHT: - ticksDelais[i] += tickLateDiagDLTR(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); + ticksDelais[i] -= tickLateDiagDLTR(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); break; case DIAGONAL_TOP_LEFT_DOWN_RIGHT: - ticksDelais[i] += tickLateDiagTLDR(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); + ticksDelais[i] -= tickLateDiagTLDR(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); break; case DIAGONAL_DOWN_RIGHT_TOP_LEFT: - ticksDelais[i] += tickLateDiagDRTL(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); + ticksDelais[i] -= tickLateDiagDRTL(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); break; case CENTER_OUT: - ticksDelais[i] += tickLateCenterOut(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); + ticksDelais[i] -= tickLateCenterOut(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); break; case CENTER_IN: - ticksDelais[i] += tickLateCenterIn(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); + ticksDelais[i] -= tickLateCenterIn(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); break; } } @@ -111,16 +111,16 @@ public class MusicPath { return ticksDelais; } - private int tickLateVerticalDown(double y) {return (int) ((1-y) * effectDuration);} - private int tickLateVerticalUp(double y) {return (int) (y * effectDuration);} - private int tickLateHorizontalToRight(double x) {return (int) ((1-x) * effectDuration);} - private int tickLateHorizontalToLeft(double x) {return (int) (x * effectDuration);} - private int tickLateDiagTRDL(double x, double y) {return (int) ((x - y) / 2d * (double) effectDuration);} - private int tickLateDiagDLTR(double x, double y) {return (int) ((-x + y) / 2d * (double) effectDuration);} - private int tickLateDiagDRTL(double x, double y) {return (int) ((x + y) / 2d * (double) effectDuration);} - private int tickLateDiagTLDR(double x, double y) {return (int) ((-x - y) / 2d * (double) effectDuration);} - private int tickLateCenterOut(double x, double y) {return (int) ((1 - (x-0.5)*(x-0.5) - (y-0.5)*(y-0.5)) * 2 * (double) effectDuration);} - private int tickLateCenterIn(double x, double y) {return (int) (((x-0.5)*(x-0.5) + (y-0.5)*(y-0.5)) * 2 * (double) effectDuration);} + private int tickLateVerticalDown(double y) {return (int) (y * effectDuration);} + private int tickLateVerticalUp(double y) {return (int) ((1-y) * effectDuration);} + private int tickLateHorizontalToRight(double x) {return (int) (x * effectDuration);} + private int tickLateHorizontalToLeft(double x) {return (int) ((1 - x) * effectDuration);} + private int tickLateDiagTRDL(double x, double y) {return (int) ((1 - x + y) / 2d * (double) effectDuration);} + private int tickLateDiagDLTR(double x, double y) {return (int) ((1 + x - y) / 2d * (double) effectDuration);} + private int tickLateDiagTLDR(double x, double y) {return (int) ((x + y) / 2d * (double) effectDuration);} + private int tickLateDiagDRTL(double x, double y) {return (int) ((2 - x - y) / 2d * (double) effectDuration);} + private int tickLateCenterOut(double x, double y) {return (int) (((x-0.5)*(x-0.5) + (y-0.5)*(y-0.5)) * 2 * (double) effectDuration);} + private int tickLateCenterIn(double x, double y) {return (int) ((0.5d - (x-0.5)*(x-0.5) - (y-0.5)*(y-0.5)) * 2 * (double) effectDuration);} public int getNumberOfLights() { return this.lightsCoords.length; diff --git a/VRGNYMusicLights/Sources/MusicPattern.java b/VRGNYMusicLights/Sources/MusicPattern.java index 6057b53..808aa7c 100644 --- a/VRGNYMusicLights/Sources/MusicPattern.java +++ b/VRGNYMusicLights/Sources/MusicPattern.java @@ -5,37 +5,48 @@ public class MusicPattern { * 1 : rise time * 2 : high time * 3 : fall time + * 4 : low time */ private int[] pattern; // in ms - private int totalLentgh; - private int[] patternTiming = new int[4]; // in ms + private int totalLength; + private int[] patternTiming = new int[5]; // in ms private long begin; // in ms private long stop; // in ms + private int repeat; public MusicPattern(int[] pattern, int repeat, long begin) { - if(pattern.length != 4) + if(pattern.length != 5) throw new InvalidPatternException(); this.pattern = pattern; - this.totalLentgh = pattern[0] + pattern[1] + pattern[2] + pattern[3]; + this.totalLength = pattern[0] + pattern[1] + pattern[2] + pattern[3] + pattern[4]; this.patternTiming[0] = pattern[0]; - for(int i=1; i<4; i++) + for(int i=1; i<5; i++) this.patternTiming[i] = this.patternTiming[i-1] + pattern[i]; this.begin = begin; - this.stop = repeat * totalLentgh; + this.stop = repeat * totalLength; + this.repeat = repeat; } + + public int[] getPatternTiming() { return patternTiming; } + public long getStop() { return stop; } + public long getBegin() { return begin; } + public int getRepeat() { return repeat; } + public int getTotalLength () { return totalLength; } public double render(long tick) { // tick in ms if(tick <= begin) return 0; if(tick >= stop) return 0; - int tickMod = (int) (tick % totalLentgh); + int tickMod = (int) (tick % totalLength); if(tickMod < patternTiming[0]) return 0; if(tickMod < patternTiming[1]) return (double) (tickMod - patternTiming[0]) / (double) (pattern[1]); if(tickMod < patternTiming[2]) return 1; - return 1 - ((double) (tickMod - patternTiming[2]) / (double) (pattern[3])); + if(tickMod < patternTiming[3]) + return 1 - ((double) (tickMod - patternTiming[2]) / (double) (pattern[3])); + return 0; } } diff --git a/VRGNYMusicLights/Sources/MusicRenderer.java b/VRGNYMusicLights/Sources/MusicRenderer.java new file mode 100644 index 0000000..d56e039 --- /dev/null +++ b/VRGNYMusicLights/Sources/MusicRenderer.java @@ -0,0 +1,54 @@ +import java.awt.Color; +import java.awt.Component; +import java.util.ArrayList; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; + +public class MusicRenderer extends JPanel implements ListCellRenderer { + private static final long serialVersionUID = 1L; + private static final Color DEFAULT_BACKGROUND = new JPanel().getBackground(); + + private TimeLineJPanel timeLine; + + public ArrayList patterns; + + public MusicRenderer(TimeLineJPanel timeLine) { + this.timeLine = timeLine; + this.patterns = new ArrayList<>(); + } + + @Override + public Component getListCellRendererComponent(JList list, Music music, int index, + boolean isSelected, boolean cellHasFocus) { + removeAll(); + + if(isSelected) { + setBackground(Color.LIGHT_GRAY); + } else { + setBackground(DEFAULT_BACKGROUND); + } + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + + JPanel infoPanel = new JPanel(); + infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.LINE_AXIS)); + infoPanel.add(new JLabel("Pattern " + String.valueOf(index) + " :")); + //TODO rigid area to follow scroll ? + infoPanel.add(Box.createHorizontalGlue()); + add(infoPanel); + + PatternJPanel pattern = new PatternJPanel(music, timeLine); + if(patterns.size() > index) + patterns.set(index, pattern); + else + patterns.add(pattern); + add(pattern); + + return this; + } +} diff --git a/VRGNYMusicLights/Sources/PatternJPanel.java b/VRGNYMusicLights/Sources/PatternJPanel.java new file mode 100644 index 0000000..52ae221 --- /dev/null +++ b/VRGNYMusicLights/Sources/PatternJPanel.java @@ -0,0 +1,63 @@ +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.swing.JPanel; + +public class PatternJPanel extends JPanel { + private static final long serialVersionUID = 1L; + private static final int HEIGHT = 50; + private static final int PADDING = 2; + public static final int ZOOM_MULTIPLIER = 10; + + private Music music; + private TimeLineJPanel timeLine; + private int end; + + public PatternJPanel(Music music, TimeLineJPanel timeLine) { + this.music = music; + this.timeLine = timeLine; + end = transformZoon(music.getMusicPattern().getStop()); + setPreferredSize(new Dimension((int) end, HEIGHT)); + } + + public void refreshPreferedSize() { + end = transformZoon(music.getMusicPattern().getStop()); + setPreferredSize(new Dimension((int) end, HEIGHT)); + } + + public int getEnd() { return end; } + public Music getMusic() { return music; } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + + g.setColor(Color.WHITE); + int begin = transformZoon(music.getMusicPattern().getBegin()); + g.fillRect(begin, 0, end, HEIGHT); + + MusicPattern pattern = music.getMusicPattern(); + g.setColor(Color.BLACK); + for(int i=0; i { + private static final long serialVersionUID = 1L; + private static final int MARK_WIDTH = 2; + + private Interface interf; + + public TimeLineJList(ListModel dataModel, Interface interf) { + super(dataModel); + this.interf = interf; + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + g.setColor(Color.BLACK); + + int maxHeight = getPreferredSize().height; + int maxWidth = getPreferredSize().width; + + int mark = transformZoon(interf.tick); + if(mark > maxWidth) + mark = maxWidth; + + g.fillRect(mark, 0, MARK_WIDTH, maxHeight); + } + + private int transformZoon(long n) { + return (int) ((double) n / (double) PatternJPanel.ZOOM_MULTIPLIER * interf.timeLinePanel.getZoomLevel()); + } +} diff --git a/VRGNYMusicLights/Sources/TimeLineJPanel.java b/VRGNYMusicLights/Sources/TimeLineJPanel.java new file mode 100644 index 0000000..dbb0f13 --- /dev/null +++ b/VRGNYMusicLights/Sources/TimeLineJPanel.java @@ -0,0 +1,146 @@ +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.DefaultListModel; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; + +public class TimeLineJPanel extends JPanel implements MouseWheelListener, FocusListener, ActionListener { + private static final long serialVersionUID = 1L; + private static final Font titleFont = new Font(new JLabel().getFont().getName(), Font.BOLD, 14); + + private static final int SCROLL_SPEED_HORIZONTAL = 30; + private static final int SCROLL_SPEED_VERTICAL = 30; + + private DefaultListModel listModel; + private double zoomLevel = 1; + + private JScrollPane scrollPane; + private MusicRenderer musicRenderer; + private Interface interf; + private JTextField currentTick; + private JLabel maxTicks; + + public TimeLineJPanel(Interface interf, MusicList list) { + this.interf = interf; + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + + // timing infos + JPanel timingPanel = new JPanel(); + timingPanel.setLayout(new BoxLayout(timingPanel, BoxLayout.LINE_AXIS)); + + JLabel title = new JLabel("Timeline : "); + title.setFont(titleFont); + timingPanel.add(title); + + currentTick = new JTextField("00:00.000", 8); + currentTick.setMaximumSize( currentTick.getPreferredSize() ); + currentTick.addFocusListener(this); + currentTick.addActionListener(this); + timingPanel.add(currentTick); + + maxTicks = new JLabel(" / 00:00.0000 (MM:ss:ms)"); + timingPanel.add(maxTicks); + + timingPanel.add(Box.createHorizontalGlue()); + + add(timingPanel); + + // timeline + + listModel = new DefaultListModel<>(); + for(Music music : list.getList()) + listModel.addElement(music); + + interf.timeLineList = new TimeLineJList(listModel, interf); + musicRenderer = new MusicRenderer(this); + interf.timeLineList.setCellRenderer(musicRenderer); + interf.timeLineList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + scrollPane = new JScrollPane(interf.timeLineList, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scrollPane.addMouseWheelListener(this); + scrollPane.setWheelScrollingEnabled(false); + scrollPane.setPreferredSize(new Dimension(800, 400)); + add(scrollPane); + } + + public double getZoomLevel() { return zoomLevel; } + + public void updateList(MusicList list) { + listModel.clear(); + for(Music music : list.getList()) + listModel.addElement(music); + } + + public void updateTick() { + currentTick.setText(Util.tickToText(interf.tick)); + long maxTick = 0; + for(PatternJPanel pattern : musicRenderer.patterns) { + pattern.refreshPreferedSize(); + long tick = pattern.getMusic().getMusicPattern().getStop(); + if(tick > maxTick) + maxTick = tick; + } + maxTicks.setText(Util.tickToText(maxTick) + " (MM:ss:ms)"); + } + + public void mouseWheelMoved(MouseWheelEvent e) { + if(e.getSource() == scrollPane) { + if (e.isControlDown()) { + if(e.getWheelRotation() < 0) + zoomLevel *= (double) e.getWheelRotation() * -1.1; + else + zoomLevel *= (double) e.getWheelRotation() / 1.1; + + int maxWidth = 0; + for(PatternJPanel pattern : musicRenderer.patterns) { + pattern.refreshPreferedSize(); + int width = pattern.getEnd(); + if(width > maxWidth) + maxWidth = width; + } + + interf.timeLineList.setPreferredSize(new Dimension(maxWidth, interf.getPreferredSize().height)); + scrollPane.repaint(); + scrollPane.getViewport().revalidate(); + } else if(e.isShiftDown()) { + JScrollBar sb = scrollPane.getHorizontalScrollBar(); + sb.setValue(sb.getValue() + e.getWheelRotation() * SCROLL_SPEED_HORIZONTAL); + } else { + JScrollBar sb = scrollPane.getVerticalScrollBar(); + sb.setValue(sb.getValue() + e.getWheelRotation() * SCROLL_SPEED_VERTICAL); + } + } + } + + @Override + public void focusLost(FocusEvent e) { + if(e.getSource() == currentTick) { + interf.tick = Util.textToTick(currentTick.getText()); + currentTick.setText(Util.tickToText(interf.tick)); + interf.computeTick(); + } + } + @Override + public void focusGained(FocusEvent e) { + if(e.getSource() == currentTick) + currentTick.setCaretPosition(currentTick.getDocument().getLength()); + } + + @Override + public void actionPerformed(ActionEvent e) { + if(e.getSource() == currentTick) + interf.getContentPane().requestFocus(); + } +} diff --git a/VRGNYMusicLights/Sources/Util.java b/VRGNYMusicLights/Sources/Util.java new file mode 100644 index 0000000..a687340 --- /dev/null +++ b/VRGNYMusicLights/Sources/Util.java @@ -0,0 +1,46 @@ + +public class Util { + public static long textToTick(String str) { + if(str == null || str.equals("")) + return 0; + String[] strs = str.split(":|\\."); + long ticks = 0; + + try { + switch (strs.length) { + case 1: + ticks += Integer.parseInt(strs[0]); + break; + case 2: + ticks += Integer.parseInt(strs[1]); + ticks += Integer.parseInt(strs[0]) * 1000; + break; + case 3: + ticks += Integer.parseInt(strs[2]); + ticks += Integer.parseInt(strs[1]) * 1000; + ticks += Integer.parseInt(strs[0]) * 60000; + break; + } + } catch (NumberFormatException e) { + return 0; + } + return ticks; + } + + public static String tickToText(long tick) { + String str = ""; + + if(tick > 5900000) + str += "99:"; + else + str += String.format("%02d", (int) ((double) tick / 60000d)) + ":"; + + tick -= (int) ((double) tick / 60000d) * 60000; + str += String.format("%02d", (int) ((double) tick / 1000d)) + "."; + + tick -= (int) ((double) tick / 1000d) * 1000; + str += String.format("%03d", tick); + + return str; + } +} -- libgit2 0.21.2