Commit 278cdee04a1413adc98d137837b0f5303da7f7b2
1 parent
a89c030d
VRGNYMusicLights timeline beginning
Showing
14 changed files
with
464 additions
and
81 deletions
Show diff stats
VRGNYMusicLights/Sources/AnimationPlayer.java
... | ... | @@ -10,8 +10,7 @@ import javax.swing.JPanel; |
10 | 10 | public class AnimationPlayer extends JPanel implements ActionListener { |
11 | 11 | private static final long serialVersionUID = 1L; |
12 | 12 | |
13 | - private LightCanvasJPanel lightCanvas; | |
14 | - private MusicList musicList; | |
13 | + private Interface interf; | |
15 | 14 | |
16 | 15 | private JButton backward; |
17 | 16 | private JButton stop; |
... | ... | @@ -19,10 +18,9 @@ public class AnimationPlayer extends JPanel implements ActionListener { |
19 | 18 | private JButton pause; |
20 | 19 | private JButton forward; |
21 | 20 | |
22 | - private long tick = 0; | |
23 | 21 | private boolean go = false; |
24 | 22 | private boolean stopClock = false; |
25 | - private static final int TICK_JUMP = 20; | |
23 | + private static final int TICK_JUMP = 10; | |
26 | 24 | private Thread tickClock = new Thread(new Runnable() { |
27 | 25 | @Override |
28 | 26 | public void run() { |
... | ... | @@ -34,25 +32,24 @@ public class AnimationPlayer extends JPanel implements ActionListener { |
34 | 32 | } |
35 | 33 | |
36 | 34 | long before = System.currentTimeMillis(); |
37 | - lightCanvas.paintLights(musicList.render(tick)); | |
38 | - tick += TICK_JUMP; | |
35 | + interf.computeTick(); | |
36 | + interf.tick += TICK_JUMP; | |
39 | 37 | long after = System.currentTimeMillis(); |
40 | 38 | |
41 | 39 | if(after - before < TICK_JUMP) { |
42 | - try { Thread.sleep(10 - after + before);} | |
40 | + try { Thread.sleep(TICK_JUMP - after + before);} | |
43 | 41 | catch (InterruptedException ignored) {} |
44 | 42 | } else if(after - before > TICK_JUMP) { |
45 | - System.err.println("Animation were slowed down by " + String.valueOf(after - before - 10) + " ticks !"); | |
43 | + System.err.println("Animation were slowed down by " + String.valueOf(after - before - TICK_JUMP) + " ticks !"); | |
46 | 44 | } |
47 | 45 | } |
48 | 46 | } |
49 | 47 | }); |
50 | 48 | public void stopTickClock() {stopClock = true;} |
51 | 49 | |
52 | - public AnimationPlayer(LightCanvasJPanel lightCanvas, MusicList musicList) { this(lightCanvas, musicList, BoxLayout.LINE_AXIS); } | |
53 | - public AnimationPlayer(LightCanvasJPanel lightCanvas, MusicList musicList, int direction) { | |
54 | - this.lightCanvas = lightCanvas; | |
55 | - this.musicList = musicList; | |
50 | + public AnimationPlayer(Interface interf) { this(interf, BoxLayout.LINE_AXIS); } | |
51 | + public AnimationPlayer(Interface interf, int direction) { | |
52 | + this.interf = interf; | |
56 | 53 | |
57 | 54 | setLayout(new BoxLayout(this, direction)); |
58 | 55 | |
... | ... | @@ -90,20 +87,22 @@ public class AnimationPlayer extends JPanel implements ActionListener { |
90 | 87 | |
91 | 88 | @Override |
92 | 89 | public void actionPerformed(ActionEvent e) { |
93 | - // TODO player actions | |
94 | 90 | if(e.getSource() == backward) { |
95 | - tick -= 500; | |
96 | - if(tick < 0) | |
97 | - tick = 0; | |
91 | + interf.tick -= 100; | |
92 | + if(interf.tick < 0) | |
93 | + interf.tick = 0; | |
94 | + interf.computeTick(); | |
98 | 95 | }else if(e.getSource() == stop) { |
99 | 96 | go = false; |
100 | - tick = 0; | |
97 | + interf.tick = 0; | |
98 | + interf.computeTick(); | |
101 | 99 | }else if(e.getSource() == play) { |
102 | 100 | go = true; |
103 | 101 | }else if(e.getSource() == pause) { |
104 | 102 | go = false; |
105 | 103 | }else if(e.getSource() == forward) { |
106 | - tick += 500; | |
104 | + interf.tick += 100; | |
105 | + interf.computeTick(); | |
107 | 106 | } |
108 | 107 | } |
109 | 108 | } | ... | ... |
VRGNYMusicLights/Sources/Interface.java
1 | 1 | import java.awt.BorderLayout; |
2 | -import java.awt.Font; | |
3 | 2 | import java.awt.event.WindowAdapter; |
4 | 3 | import java.awt.event.WindowEvent; |
5 | 4 | |
6 | 5 | import javax.swing.JFrame; |
7 | -import javax.swing.JLabel; | |
8 | 6 | import javax.swing.JPanel; |
9 | 7 | |
10 | 8 | public class Interface extends JFrame{ |
11 | 9 | private static final long serialVersionUID = 1L; |
12 | - private static final Font titleFont = new Font(new JLabel().getFont().getName(), Font.BOLD, 14); | |
13 | - private static final Font defaultFont = new Font(new JLabel().getFont().getName(), Font.PLAIN, new JLabel().getFont().getSize()); | |
10 | + //private static final Font titleFont = new Font(new JLabel().getFont().getName(), Font.BOLD, 14); | |
11 | + //private static final Font defaultFont = new Font(new JLabel().getFont().getName(), Font.PLAIN, new JLabel().getFont().getSize()); | |
14 | 12 | |
15 | - private MusicList musicList; | |
16 | - private AnimationPlayer animPlayer; | |
13 | + protected MusicList musicList; | |
14 | + protected AnimationPlayer animPlayer; | |
15 | + protected TimeLineJPanel timeLinePanel; | |
16 | + protected TimeLineJList timeLineList; | |
17 | + protected LightCanvasJPanel lightCanvas; | |
18 | + protected long tick = 0; | |
17 | 19 | |
18 | 20 | public Interface(MusicList musicList, final Runnable executeOnClose) { |
19 | 21 | super("VRGNYMusicLights"); |
... | ... | @@ -22,6 +24,7 @@ public class Interface extends JFrame{ |
22 | 24 | populateWindow(); |
23 | 25 | pack(); |
24 | 26 | setLocationRelativeTo(null); // center window |
27 | + getContentPane().requestFocus(); | |
25 | 28 | |
26 | 29 | addWindowListener(new WindowAdapter() { |
27 | 30 | @Override |
... | ... | @@ -35,34 +38,18 @@ public class Interface extends JFrame{ |
35 | 38 | }); |
36 | 39 | } |
37 | 40 | |
41 | + protected void computeTick() { | |
42 | + lightCanvas.paintLights(musicList.render(tick)); | |
43 | + timeLineList.repaint(); | |
44 | + timeLinePanel.updateTick(); | |
45 | + } | |
46 | + | |
38 | 47 | private void populateWindow() { |
39 | 48 | JPanel mainPanel = new JPanel(new BorderLayout()); |
40 | - addPlayPanel(mainPanel); | |
41 | - addTimeLine(mainPanel); | |
49 | + timeLinePanel = new TimeLineJPanel(this, musicList); | |
50 | + mainPanel.add(timeLinePanel, BorderLayout.CENTER); | |
51 | + lightCanvas = new LightCanvasJPanel(); | |
52 | + mainPanel.add(new PlayJPanel(this, lightCanvas), BorderLayout.SOUTH); | |
42 | 53 | add(mainPanel); |
43 | 54 | } |
44 | - | |
45 | - private void addPlayPanel(JPanel parent) { | |
46 | - JPanel playPanel = new JPanel(new BorderLayout()); | |
47 | - | |
48 | - // title | |
49 | - JLabel title = new JLabel("Visualizer :"); | |
50 | - title.setFont(titleFont); | |
51 | - playPanel.add(title, BorderLayout.NORTH); | |
52 | - | |
53 | - // lights | |
54 | - LightCanvasJPanel lightCanvas = new LightCanvasJPanel(); | |
55 | - playPanel.add(lightCanvas, BorderLayout.CENTER); | |
56 | - | |
57 | - // controls | |
58 | - animPlayer = new AnimationPlayer(lightCanvas, musicList); | |
59 | - animPlayer.setAlignmentX(CENTER_ALIGNMENT); | |
60 | - playPanel.add(animPlayer, BorderLayout.SOUTH); | |
61 | - | |
62 | - parent.add(playPanel, BorderLayout.SOUTH); | |
63 | - } | |
64 | - | |
65 | - private void addTimeLine(JPanel parent) { | |
66 | - JPanel timeLine = new JPanel(); | |
67 | - } | |
68 | 55 | } | ... | ... |
VRGNYMusicLights/Sources/InvalidPatternException.java
... | ... | @@ -3,6 +3,6 @@ public class InvalidPatternException extends RuntimeException { |
3 | 3 | private static final long serialVersionUID = 1L; |
4 | 4 | |
5 | 5 | public InvalidPatternException() { |
6 | - super("Invalid pattern given. Length must be equal to 4."); | |
6 | + super("Invalid pattern given. Length must be equal to 5."); | |
7 | 7 | } |
8 | 8 | } | ... | ... |
VRGNYMusicLights/Sources/Main.java
... | ... | @@ -2,6 +2,7 @@ import javax.swing.JOptionPane; |
2 | 2 | |
3 | 3 | /* TODO list : |
4 | 4 | * - keyboard listener for animation player (play / pause = space, forward = semicolon, backward = comma, stop = backspace) |
5 | + * - pattern timeline info to follow scroll horizontal ? | |
5 | 6 | */ |
6 | 7 | public class Main { |
7 | 8 | public static void main(String[] args) throws InterruptedException { |
... | ... | @@ -22,8 +23,13 @@ public class Main { |
22 | 23 | MusicList musicList = new MusicList(null); |
23 | 24 | musicList.addMusic( |
24 | 25 | new Music( |
25 | - new MusicPattern(new int[] {1000, 0, 0, 1000}, 1000, 0), | |
26 | - new MusicPath(MusicPath.CENTER_IN, 1000), | |
26 | + new MusicPattern(new int[] {0, 10, 100, 10, 100}, 100, 1000), | |
27 | + new MusicPath(MusicPath.CENTER_OUT, 1000), | |
28 | + 1)); | |
29 | + musicList.addMusic( | |
30 | + new Music( | |
31 | + new MusicPattern(new int[] {0, 10, 100, 10, 100}, 1, 0), | |
32 | + new MusicPath(MusicPath.CENTER_OUT, 1000), | |
27 | 33 | 1)); |
28 | 34 | |
29 | 35 | Interface i = new Interface(musicList, new Runnable() { | ... | ... |
VRGNYMusicLights/Sources/Music.java
... | ... | @@ -10,6 +10,8 @@ public class Music { |
10 | 10 | this.volume = volume; |
11 | 11 | } |
12 | 12 | |
13 | + public MusicPattern getMusicPattern() { return pattern; } | |
14 | + | |
13 | 15 | public double[] render(long tick) { |
14 | 16 | double[] lights = new double[lightTickDelais.length]; |
15 | 17 | for(int i=0; i<lights.length; i++) | ... | ... |
VRGNYMusicLights/Sources/MusicList.java
VRGNYMusicLights/Sources/MusicPath.java
... | ... | @@ -75,34 +75,34 @@ public class MusicPath { |
75 | 75 | || animation == CENTER_IN) { |
76 | 76 | switch (animation) { |
77 | 77 | case VERTICAL_DOWN: |
78 | - ticksDelais[i] += tickLateVerticalDown(LIGHT_COORDS[i][1]); | |
78 | + ticksDelais[i] -= tickLateVerticalDown(LIGHT_COORDS[i][1]); | |
79 | 79 | break; |
80 | 80 | case VERTICAL_UP: |
81 | - ticksDelais[i] += tickLateVerticalUp(LIGHT_COORDS[i][1]); | |
81 | + ticksDelais[i] -= tickLateVerticalUp(LIGHT_COORDS[i][1]); | |
82 | 82 | break; |
83 | 83 | case HORIZONTAL_TO_LEFT: |
84 | - ticksDelais[i] += tickLateHorizontalToLeft(LIGHT_COORDS[i][0]); | |
84 | + ticksDelais[i] -= tickLateHorizontalToLeft(LIGHT_COORDS[i][0]); | |
85 | 85 | break; |
86 | 86 | case HORIZONTAL_TO_RIGHT: |
87 | - ticksDelais[i] += tickLateHorizontalToRight(LIGHT_COORDS[i][0]); | |
87 | + ticksDelais[i] -= tickLateHorizontalToRight(LIGHT_COORDS[i][0]); | |
88 | 88 | break; |
89 | 89 | case DIAGONAL_TOP_RIGHT_DOWN_LEFT: |
90 | - ticksDelais[i] += tickLateDiagTRDL(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
90 | + ticksDelais[i] -= tickLateDiagTRDL(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
91 | 91 | break; |
92 | 92 | case DIAGONAL_DOWN_LEFT_TOP_RIGHT: |
93 | - ticksDelais[i] += tickLateDiagDLTR(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
93 | + ticksDelais[i] -= tickLateDiagDLTR(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
94 | 94 | break; |
95 | 95 | case DIAGONAL_TOP_LEFT_DOWN_RIGHT: |
96 | - ticksDelais[i] += tickLateDiagTLDR(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
96 | + ticksDelais[i] -= tickLateDiagTLDR(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
97 | 97 | break; |
98 | 98 | case DIAGONAL_DOWN_RIGHT_TOP_LEFT: |
99 | - ticksDelais[i] += tickLateDiagDRTL(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
99 | + ticksDelais[i] -= tickLateDiagDRTL(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
100 | 100 | break; |
101 | 101 | case CENTER_OUT: |
102 | - ticksDelais[i] += tickLateCenterOut(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
102 | + ticksDelais[i] -= tickLateCenterOut(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
103 | 103 | break; |
104 | 104 | case CENTER_IN: |
105 | - ticksDelais[i] += tickLateCenterIn(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
105 | + ticksDelais[i] -= tickLateCenterIn(LIGHT_COORDS[i][0], LIGHT_COORDS[i][1]); | |
106 | 106 | break; |
107 | 107 | } |
108 | 108 | } |
... | ... | @@ -111,16 +111,16 @@ public class MusicPath { |
111 | 111 | return ticksDelais; |
112 | 112 | } |
113 | 113 | |
114 | - private int tickLateVerticalDown(double y) {return (int) ((1-y) * effectDuration);} | |
115 | - private int tickLateVerticalUp(double y) {return (int) (y * effectDuration);} | |
116 | - private int tickLateHorizontalToRight(double x) {return (int) ((1-x) * effectDuration);} | |
117 | - private int tickLateHorizontalToLeft(double x) {return (int) (x * effectDuration);} | |
118 | - private int tickLateDiagTRDL(double x, double y) {return (int) ((x - y) / 2d * (double) effectDuration);} | |
119 | - private int tickLateDiagDLTR(double x, double y) {return (int) ((-x + y) / 2d * (double) effectDuration);} | |
120 | - private int tickLateDiagDRTL(double x, double y) {return (int) ((x + y) / 2d * (double) effectDuration);} | |
121 | - private int tickLateDiagTLDR(double x, double y) {return (int) ((-x - y) / 2d * (double) effectDuration);} | |
122 | - 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);} | |
123 | - private int tickLateCenterIn(double x, double y) {return (int) (((x-0.5)*(x-0.5) + (y-0.5)*(y-0.5)) * 2 * (double) effectDuration);} | |
114 | + private int tickLateVerticalDown(double y) {return (int) (y * effectDuration);} | |
115 | + private int tickLateVerticalUp(double y) {return (int) ((1-y) * effectDuration);} | |
116 | + private int tickLateHorizontalToRight(double x) {return (int) (x * effectDuration);} | |
117 | + private int tickLateHorizontalToLeft(double x) {return (int) ((1 - x) * effectDuration);} | |
118 | + private int tickLateDiagTRDL(double x, double y) {return (int) ((1 - x + y) / 2d * (double) effectDuration);} | |
119 | + private int tickLateDiagDLTR(double x, double y) {return (int) ((1 + x - y) / 2d * (double) effectDuration);} | |
120 | + private int tickLateDiagTLDR(double x, double y) {return (int) ((x + y) / 2d * (double) effectDuration);} | |
121 | + private int tickLateDiagDRTL(double x, double y) {return (int) ((2 - x - y) / 2d * (double) effectDuration);} | |
122 | + private int tickLateCenterOut(double x, double y) {return (int) (((x-0.5)*(x-0.5) + (y-0.5)*(y-0.5)) * 2 * (double) effectDuration);} | |
123 | + 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);} | |
124 | 124 | |
125 | 125 | public int getNumberOfLights() { |
126 | 126 | return this.lightsCoords.length; | ... | ... |
VRGNYMusicLights/Sources/MusicPattern.java
... | ... | @@ -5,37 +5,48 @@ public class MusicPattern { |
5 | 5 | * 1 : rise time |
6 | 6 | * 2 : high time |
7 | 7 | * 3 : fall time |
8 | + * 4 : low time | |
8 | 9 | */ |
9 | 10 | private int[] pattern; // in ms |
10 | - private int totalLentgh; | |
11 | - private int[] patternTiming = new int[4]; // in ms | |
11 | + private int totalLength; | |
12 | + private int[] patternTiming = new int[5]; // in ms | |
12 | 13 | private long begin; // in ms |
13 | 14 | private long stop; // in ms |
15 | + private int repeat; | |
14 | 16 | |
15 | 17 | public MusicPattern(int[] pattern, int repeat, long begin) { |
16 | - if(pattern.length != 4) | |
18 | + if(pattern.length != 5) | |
17 | 19 | throw new InvalidPatternException(); |
18 | 20 | this.pattern = pattern; |
19 | - this.totalLentgh = pattern[0] + pattern[1] + pattern[2] + pattern[3]; | |
21 | + this.totalLength = pattern[0] + pattern[1] + pattern[2] + pattern[3] + pattern[4]; | |
20 | 22 | this.patternTiming[0] = pattern[0]; |
21 | - for(int i=1; i<4; i++) | |
23 | + for(int i=1; i<5; i++) | |
22 | 24 | this.patternTiming[i] = this.patternTiming[i-1] + pattern[i]; |
23 | 25 | this.begin = begin; |
24 | - this.stop = repeat * totalLentgh; | |
26 | + this.stop = repeat * totalLength; | |
27 | + this.repeat = repeat; | |
25 | 28 | } |
29 | + | |
30 | + public int[] getPatternTiming() { return patternTiming; } | |
31 | + public long getStop() { return stop; } | |
32 | + public long getBegin() { return begin; } | |
33 | + public int getRepeat() { return repeat; } | |
34 | + public int getTotalLength () { return totalLength; } | |
26 | 35 | |
27 | 36 | public double render(long tick) { // tick in ms |
28 | 37 | if(tick <= begin) |
29 | 38 | return 0; |
30 | 39 | if(tick >= stop) |
31 | 40 | return 0; |
32 | - int tickMod = (int) (tick % totalLentgh); | |
41 | + int tickMod = (int) (tick % totalLength); | |
33 | 42 | if(tickMod < patternTiming[0]) |
34 | 43 | return 0; |
35 | 44 | if(tickMod < patternTiming[1]) |
36 | 45 | return (double) (tickMod - patternTiming[0]) / (double) (pattern[1]); |
37 | 46 | if(tickMod < patternTiming[2]) |
38 | 47 | return 1; |
39 | - return 1 - ((double) (tickMod - patternTiming[2]) / (double) (pattern[3])); | |
48 | + if(tickMod < patternTiming[3]) | |
49 | + return 1 - ((double) (tickMod - patternTiming[2]) / (double) (pattern[3])); | |
50 | + return 0; | |
40 | 51 | } |
41 | 52 | } | ... | ... |
... | ... | @@ -0,0 +1,54 @@ |
1 | +import java.awt.Color; | |
2 | +import java.awt.Component; | |
3 | +import java.util.ArrayList; | |
4 | + | |
5 | +import javax.swing.Box; | |
6 | +import javax.swing.BoxLayout; | |
7 | +import javax.swing.JLabel; | |
8 | +import javax.swing.JList; | |
9 | +import javax.swing.JPanel; | |
10 | +import javax.swing.ListCellRenderer; | |
11 | + | |
12 | +public class MusicRenderer extends JPanel implements ListCellRenderer<Music> { | |
13 | + private static final long serialVersionUID = 1L; | |
14 | + private static final Color DEFAULT_BACKGROUND = new JPanel().getBackground(); | |
15 | + | |
16 | + private TimeLineJPanel timeLine; | |
17 | + | |
18 | + public ArrayList<PatternJPanel> patterns; | |
19 | + | |
20 | + public MusicRenderer(TimeLineJPanel timeLine) { | |
21 | + this.timeLine = timeLine; | |
22 | + this.patterns = new ArrayList<>(); | |
23 | + } | |
24 | + | |
25 | + @Override | |
26 | + public Component getListCellRendererComponent(JList<? extends Music> list, Music music, int index, | |
27 | + boolean isSelected, boolean cellHasFocus) { | |
28 | + removeAll(); | |
29 | + | |
30 | + if(isSelected) { | |
31 | + setBackground(Color.LIGHT_GRAY); | |
32 | + } else { | |
33 | + setBackground(DEFAULT_BACKGROUND); | |
34 | + } | |
35 | + | |
36 | + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); | |
37 | + | |
38 | + JPanel infoPanel = new JPanel(); | |
39 | + infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.LINE_AXIS)); | |
40 | + infoPanel.add(new JLabel("Pattern " + String.valueOf(index) + " :")); | |
41 | + //TODO rigid area to follow scroll ? | |
42 | + infoPanel.add(Box.createHorizontalGlue()); | |
43 | + add(infoPanel); | |
44 | + | |
45 | + PatternJPanel pattern = new PatternJPanel(music, timeLine); | |
46 | + if(patterns.size() > index) | |
47 | + patterns.set(index, pattern); | |
48 | + else | |
49 | + patterns.add(pattern); | |
50 | + add(pattern); | |
51 | + | |
52 | + return this; | |
53 | + } | |
54 | +} | ... | ... |
... | ... | @@ -0,0 +1,63 @@ |
1 | +import java.awt.Color; | |
2 | +import java.awt.Dimension; | |
3 | +import java.awt.Graphics; | |
4 | + | |
5 | +import javax.swing.JPanel; | |
6 | + | |
7 | +public class PatternJPanel extends JPanel { | |
8 | + private static final long serialVersionUID = 1L; | |
9 | + private static final int HEIGHT = 50; | |
10 | + private static final int PADDING = 2; | |
11 | + public static final int ZOOM_MULTIPLIER = 10; | |
12 | + | |
13 | + private Music music; | |
14 | + private TimeLineJPanel timeLine; | |
15 | + private int end; | |
16 | + | |
17 | + public PatternJPanel(Music music, TimeLineJPanel timeLine) { | |
18 | + this.music = music; | |
19 | + this.timeLine = timeLine; | |
20 | + end = transformZoon(music.getMusicPattern().getStop()); | |
21 | + setPreferredSize(new Dimension((int) end, HEIGHT)); | |
22 | + } | |
23 | + | |
24 | + public void refreshPreferedSize() { | |
25 | + end = transformZoon(music.getMusicPattern().getStop()); | |
26 | + setPreferredSize(new Dimension((int) end, HEIGHT)); | |
27 | + } | |
28 | + | |
29 | + public int getEnd() { return end; } | |
30 | + public Music getMusic() { return music; } | |
31 | + | |
32 | + @Override | |
33 | + protected void paintComponent(Graphics g) { | |
34 | + super.paintComponent(g); | |
35 | + | |
36 | + g.setColor(Color.WHITE); | |
37 | + int begin = transformZoon(music.getMusicPattern().getBegin()); | |
38 | + g.fillRect(begin, 0, end, HEIGHT); | |
39 | + | |
40 | + MusicPattern pattern = music.getMusicPattern(); | |
41 | + g.setColor(Color.BLACK); | |
42 | + for(int i=0; i<pattern.getRepeat(); i++) { | |
43 | + int repeatAddition = transformZoon(pattern.getTotalLength() * i) + begin; | |
44 | + g.drawLine(repeatAddition, HEIGHT - PADDING, | |
45 | + transformZoon(pattern.getPatternTiming()[0]) + repeatAddition, HEIGHT - PADDING); | |
46 | + g.drawLine(transformZoon(pattern.getPatternTiming()[0]) + repeatAddition, HEIGHT - PADDING, | |
47 | + transformZoon(pattern.getPatternTiming()[1]) + repeatAddition, PADDING); | |
48 | + g.drawLine(transformZoon(pattern.getPatternTiming()[1]) + repeatAddition, PADDING, | |
49 | + transformZoon(pattern.getPatternTiming()[2]) + repeatAddition, PADDING); | |
50 | + g.drawLine(transformZoon(pattern.getPatternTiming()[2]) + repeatAddition, PADDING, | |
51 | + transformZoon(pattern.getPatternTiming()[3]) + repeatAddition, HEIGHT - PADDING); | |
52 | + g.drawLine(transformZoon(pattern.getPatternTiming()[3]) + repeatAddition, HEIGHT - PADDING, | |
53 | + transformZoon(pattern.getPatternTiming()[4]) + repeatAddition, HEIGHT - PADDING); | |
54 | + } | |
55 | + } | |
56 | + | |
57 | + private int transformZoon(int n) { | |
58 | + return transformZoon((long) n); | |
59 | + } | |
60 | + private int transformZoon(long n) { | |
61 | + return (int) ((double) n / (double) ZOOM_MULTIPLIER * timeLine.getZoomLevel()); | |
62 | + } | |
63 | +} | ... | ... |
... | ... | @@ -0,0 +1,32 @@ |
1 | +import java.awt.BorderLayout; | |
2 | +import java.awt.Font; | |
3 | + | |
4 | +import javax.swing.Box; | |
5 | +import javax.swing.BoxLayout; | |
6 | +import javax.swing.JLabel; | |
7 | +import javax.swing.JPanel; | |
8 | + | |
9 | +public class PlayJPanel extends JPanel { | |
10 | + private static final long serialVersionUID = 1L; | |
11 | + private static final Font titleFont = new Font(new JLabel().getFont().getName(), Font.BOLD, 14); | |
12 | + | |
13 | + public PlayJPanel(Interface interf, LightCanvasJPanel lightCanvas) { | |
14 | + super(new BorderLayout()); | |
15 | + | |
16 | + // title | |
17 | + JLabel title = new JLabel("Visualizer :"); | |
18 | + title.setFont(titleFont); | |
19 | + add(title, BorderLayout.NORTH); | |
20 | + | |
21 | + // lights | |
22 | + JPanel centerPanel = new JPanel(); | |
23 | + centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.LINE_AXIS)); | |
24 | + centerPanel.add(Box.createHorizontalGlue()); | |
25 | + centerPanel.add(lightCanvas); | |
26 | + add(centerPanel, BorderLayout.CENTER); | |
27 | + | |
28 | + // controls | |
29 | + interf.animPlayer = new AnimationPlayer(interf); | |
30 | + add(interf.animPlayer, BorderLayout.SOUTH); | |
31 | + } | |
32 | +} | ... | ... |
... | ... | @@ -0,0 +1,36 @@ |
1 | +import java.awt.Color; | |
2 | +import java.awt.Graphics; | |
3 | + | |
4 | +import javax.swing.JList; | |
5 | +import javax.swing.ListModel; | |
6 | + | |
7 | +public class TimeLineJList extends JList<Music> { | |
8 | + private static final long serialVersionUID = 1L; | |
9 | + private static final int MARK_WIDTH = 2; | |
10 | + | |
11 | + private Interface interf; | |
12 | + | |
13 | + public TimeLineJList(ListModel<Music> dataModel, Interface interf) { | |
14 | + super(dataModel); | |
15 | + this.interf = interf; | |
16 | + } | |
17 | + | |
18 | + @Override | |
19 | + protected void paintComponent(Graphics g) { | |
20 | + super.paintComponent(g); | |
21 | + g.setColor(Color.BLACK); | |
22 | + | |
23 | + int maxHeight = getPreferredSize().height; | |
24 | + int maxWidth = getPreferredSize().width; | |
25 | + | |
26 | + int mark = transformZoon(interf.tick); | |
27 | + if(mark > maxWidth) | |
28 | + mark = maxWidth; | |
29 | + | |
30 | + g.fillRect(mark, 0, MARK_WIDTH, maxHeight); | |
31 | + } | |
32 | + | |
33 | + private int transformZoon(long n) { | |
34 | + return (int) ((double) n / (double) PatternJPanel.ZOOM_MULTIPLIER * interf.timeLinePanel.getZoomLevel()); | |
35 | + } | |
36 | +} | ... | ... |
... | ... | @@ -0,0 +1,146 @@ |
1 | +import java.awt.Dimension; | |
2 | +import java.awt.Font; | |
3 | +import java.awt.event.ActionEvent; | |
4 | +import java.awt.event.ActionListener; | |
5 | +import java.awt.event.FocusEvent; | |
6 | +import java.awt.event.FocusListener; | |
7 | +import java.awt.event.MouseWheelEvent; | |
8 | +import java.awt.event.MouseWheelListener; | |
9 | + | |
10 | +import javax.swing.Box; | |
11 | +import javax.swing.BoxLayout; | |
12 | +import javax.swing.DefaultListModel; | |
13 | +import javax.swing.JLabel; | |
14 | +import javax.swing.JPanel; | |
15 | +import javax.swing.JScrollBar; | |
16 | +import javax.swing.JScrollPane; | |
17 | +import javax.swing.JTextField; | |
18 | +import javax.swing.ListSelectionModel; | |
19 | + | |
20 | +public class TimeLineJPanel extends JPanel implements MouseWheelListener, FocusListener, ActionListener { | |
21 | + private static final long serialVersionUID = 1L; | |
22 | + private static final Font titleFont = new Font(new JLabel().getFont().getName(), Font.BOLD, 14); | |
23 | + | |
24 | + private static final int SCROLL_SPEED_HORIZONTAL = 30; | |
25 | + private static final int SCROLL_SPEED_VERTICAL = 30; | |
26 | + | |
27 | + private DefaultListModel<Music> listModel; | |
28 | + private double zoomLevel = 1; | |
29 | + | |
30 | + private JScrollPane scrollPane; | |
31 | + private MusicRenderer musicRenderer; | |
32 | + private Interface interf; | |
33 | + private JTextField currentTick; | |
34 | + private JLabel maxTicks; | |
35 | + | |
36 | + public TimeLineJPanel(Interface interf, MusicList list) { | |
37 | + this.interf = interf; | |
38 | + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); | |
39 | + | |
40 | + // timing infos | |
41 | + JPanel timingPanel = new JPanel(); | |
42 | + timingPanel.setLayout(new BoxLayout(timingPanel, BoxLayout.LINE_AXIS)); | |
43 | + | |
44 | + JLabel title = new JLabel("Timeline : "); | |
45 | + title.setFont(titleFont); | |
46 | + timingPanel.add(title); | |
47 | + | |
48 | + currentTick = new JTextField("00:00.000", 8); | |
49 | + currentTick.setMaximumSize( currentTick.getPreferredSize() ); | |
50 | + currentTick.addFocusListener(this); | |
51 | + currentTick.addActionListener(this); | |
52 | + timingPanel.add(currentTick); | |
53 | + | |
54 | + maxTicks = new JLabel(" / 00:00.0000 (MM:ss:ms)"); | |
55 | + timingPanel.add(maxTicks); | |
56 | + | |
57 | + timingPanel.add(Box.createHorizontalGlue()); | |
58 | + | |
59 | + add(timingPanel); | |
60 | + | |
61 | + // timeline | |
62 | + | |
63 | + listModel = new DefaultListModel<>(); | |
64 | + for(Music music : list.getList()) | |
65 | + listModel.addElement(music); | |
66 | + | |
67 | + interf.timeLineList = new TimeLineJList(listModel, interf); | |
68 | + musicRenderer = new MusicRenderer(this); | |
69 | + interf.timeLineList.setCellRenderer(musicRenderer); | |
70 | + interf.timeLineList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); | |
71 | + scrollPane = new JScrollPane(interf.timeLineList, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); | |
72 | + scrollPane.addMouseWheelListener(this); | |
73 | + scrollPane.setWheelScrollingEnabled(false); | |
74 | + scrollPane.setPreferredSize(new Dimension(800, 400)); | |
75 | + add(scrollPane); | |
76 | + } | |
77 | + | |
78 | + public double getZoomLevel() { return zoomLevel; } | |
79 | + | |
80 | + public void updateList(MusicList list) { | |
81 | + listModel.clear(); | |
82 | + for(Music music : list.getList()) | |
83 | + listModel.addElement(music); | |
84 | + } | |
85 | + | |
86 | + public void updateTick() { | |
87 | + currentTick.setText(Util.tickToText(interf.tick)); | |
88 | + long maxTick = 0; | |
89 | + for(PatternJPanel pattern : musicRenderer.patterns) { | |
90 | + pattern.refreshPreferedSize(); | |
91 | + long tick = pattern.getMusic().getMusicPattern().getStop(); | |
92 | + if(tick > maxTick) | |
93 | + maxTick = tick; | |
94 | + } | |
95 | + maxTicks.setText(Util.tickToText(maxTick) + " (MM:ss:ms)"); | |
96 | + } | |
97 | + | |
98 | + public void mouseWheelMoved(MouseWheelEvent e) { | |
99 | + if(e.getSource() == scrollPane) { | |
100 | + if (e.isControlDown()) { | |
101 | + if(e.getWheelRotation() < 0) | |
102 | + zoomLevel *= (double) e.getWheelRotation() * -1.1; | |
103 | + else | |
104 | + zoomLevel *= (double) e.getWheelRotation() / 1.1; | |
105 | + | |
106 | + int maxWidth = 0; | |
107 | + for(PatternJPanel pattern : musicRenderer.patterns) { | |
108 | + pattern.refreshPreferedSize(); | |
109 | + int width = pattern.getEnd(); | |
110 | + if(width > maxWidth) | |
111 | + maxWidth = width; | |
112 | + } | |
113 | + | |
114 | + interf.timeLineList.setPreferredSize(new Dimension(maxWidth, interf.getPreferredSize().height)); | |
115 | + scrollPane.repaint(); | |
116 | + scrollPane.getViewport().revalidate(); | |
117 | + } else if(e.isShiftDown()) { | |
118 | + JScrollBar sb = scrollPane.getHorizontalScrollBar(); | |
119 | + sb.setValue(sb.getValue() + e.getWheelRotation() * SCROLL_SPEED_HORIZONTAL); | |
120 | + } else { | |
121 | + JScrollBar sb = scrollPane.getVerticalScrollBar(); | |
122 | + sb.setValue(sb.getValue() + e.getWheelRotation() * SCROLL_SPEED_VERTICAL); | |
123 | + } | |
124 | + } | |
125 | + } | |
126 | + | |
127 | + @Override | |
128 | + public void focusLost(FocusEvent e) { | |
129 | + if(e.getSource() == currentTick) { | |
130 | + interf.tick = Util.textToTick(currentTick.getText()); | |
131 | + currentTick.setText(Util.tickToText(interf.tick)); | |
132 | + interf.computeTick(); | |
133 | + } | |
134 | + } | |
135 | + @Override | |
136 | + public void focusGained(FocusEvent e) { | |
137 | + if(e.getSource() == currentTick) | |
138 | + currentTick.setCaretPosition(currentTick.getDocument().getLength()); | |
139 | + } | |
140 | + | |
141 | + @Override | |
142 | + public void actionPerformed(ActionEvent e) { | |
143 | + if(e.getSource() == currentTick) | |
144 | + interf.getContentPane().requestFocus(); | |
145 | + } | |
146 | +} | ... | ... |
... | ... | @@ -0,0 +1,46 @@ |
1 | + | |
2 | +public class Util { | |
3 | + public static long textToTick(String str) { | |
4 | + if(str == null || str.equals("")) | |
5 | + return 0; | |
6 | + String[] strs = str.split(":|\\."); | |
7 | + long ticks = 0; | |
8 | + | |
9 | + try { | |
10 | + switch (strs.length) { | |
11 | + case 1: | |
12 | + ticks += Integer.parseInt(strs[0]); | |
13 | + break; | |
14 | + case 2: | |
15 | + ticks += Integer.parseInt(strs[1]); | |
16 | + ticks += Integer.parseInt(strs[0]) * 1000; | |
17 | + break; | |
18 | + case 3: | |
19 | + ticks += Integer.parseInt(strs[2]); | |
20 | + ticks += Integer.parseInt(strs[1]) * 1000; | |
21 | + ticks += Integer.parseInt(strs[0]) * 60000; | |
22 | + break; | |
23 | + } | |
24 | + } catch (NumberFormatException e) { | |
25 | + return 0; | |
26 | + } | |
27 | + return ticks; | |
28 | + } | |
29 | + | |
30 | + public static String tickToText(long tick) { | |
31 | + String str = ""; | |
32 | + | |
33 | + if(tick > 5900000) | |
34 | + str += "99:"; | |
35 | + else | |
36 | + str += String.format("%02d", (int) ((double) tick / 60000d)) + ":"; | |
37 | + | |
38 | + tick -= (int) ((double) tick / 60000d) * 60000; | |
39 | + str += String.format("%02d", (int) ((double) tick / 1000d)) + "."; | |
40 | + | |
41 | + tick -= (int) ((double) tick / 1000d) * 1000; | |
42 | + str += String.format("%03d", tick); | |
43 | + | |
44 | + return str; | |
45 | + } | |
46 | +} | ... | ... |