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,8 +10,7 @@ import javax.swing.JPanel; | ||
10 | public class AnimationPlayer extends JPanel implements ActionListener { | 10 | public class AnimationPlayer extends JPanel implements ActionListener { |
11 | private static final long serialVersionUID = 1L; | 11 | private static final long serialVersionUID = 1L; |
12 | 12 | ||
13 | - private LightCanvasJPanel lightCanvas; | ||
14 | - private MusicList musicList; | 13 | + private Interface interf; |
15 | 14 | ||
16 | private JButton backward; | 15 | private JButton backward; |
17 | private JButton stop; | 16 | private JButton stop; |
@@ -19,10 +18,9 @@ public class AnimationPlayer extends JPanel implements ActionListener { | @@ -19,10 +18,9 @@ public class AnimationPlayer extends JPanel implements ActionListener { | ||
19 | private JButton pause; | 18 | private JButton pause; |
20 | private JButton forward; | 19 | private JButton forward; |
21 | 20 | ||
22 | - private long tick = 0; | ||
23 | private boolean go = false; | 21 | private boolean go = false; |
24 | private boolean stopClock = false; | 22 | private boolean stopClock = false; |
25 | - private static final int TICK_JUMP = 20; | 23 | + private static final int TICK_JUMP = 10; |
26 | private Thread tickClock = new Thread(new Runnable() { | 24 | private Thread tickClock = new Thread(new Runnable() { |
27 | @Override | 25 | @Override |
28 | public void run() { | 26 | public void run() { |
@@ -34,25 +32,24 @@ public class AnimationPlayer extends JPanel implements ActionListener { | @@ -34,25 +32,24 @@ public class AnimationPlayer extends JPanel implements ActionListener { | ||
34 | } | 32 | } |
35 | 33 | ||
36 | long before = System.currentTimeMillis(); | 34 | long before = System.currentTimeMillis(); |
37 | - lightCanvas.paintLights(musicList.render(tick)); | ||
38 | - tick += TICK_JUMP; | 35 | + interf.computeTick(); |
36 | + interf.tick += TICK_JUMP; | ||
39 | long after = System.currentTimeMillis(); | 37 | long after = System.currentTimeMillis(); |
40 | 38 | ||
41 | if(after - before < TICK_JUMP) { | 39 | if(after - before < TICK_JUMP) { |
42 | - try { Thread.sleep(10 - after + before);} | 40 | + try { Thread.sleep(TICK_JUMP - after + before);} |
43 | catch (InterruptedException ignored) {} | 41 | catch (InterruptedException ignored) {} |
44 | } else if(after - before > TICK_JUMP) { | 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 | public void stopTickClock() {stopClock = true;} | 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 | setLayout(new BoxLayout(this, direction)); | 54 | setLayout(new BoxLayout(this, direction)); |
58 | 55 | ||
@@ -90,20 +87,22 @@ public class AnimationPlayer extends JPanel implements ActionListener { | @@ -90,20 +87,22 @@ public class AnimationPlayer extends JPanel implements ActionListener { | ||
90 | 87 | ||
91 | @Override | 88 | @Override |
92 | public void actionPerformed(ActionEvent e) { | 89 | public void actionPerformed(ActionEvent e) { |
93 | - // TODO player actions | ||
94 | if(e.getSource() == backward) { | 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 | }else if(e.getSource() == stop) { | 95 | }else if(e.getSource() == stop) { |
99 | go = false; | 96 | go = false; |
100 | - tick = 0; | 97 | + interf.tick = 0; |
98 | + interf.computeTick(); | ||
101 | }else if(e.getSource() == play) { | 99 | }else if(e.getSource() == play) { |
102 | go = true; | 100 | go = true; |
103 | }else if(e.getSource() == pause) { | 101 | }else if(e.getSource() == pause) { |
104 | go = false; | 102 | go = false; |
105 | }else if(e.getSource() == forward) { | 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 | import java.awt.BorderLayout; | 1 | import java.awt.BorderLayout; |
2 | -import java.awt.Font; | ||
3 | import java.awt.event.WindowAdapter; | 2 | import java.awt.event.WindowAdapter; |
4 | import java.awt.event.WindowEvent; | 3 | import java.awt.event.WindowEvent; |
5 | 4 | ||
6 | import javax.swing.JFrame; | 5 | import javax.swing.JFrame; |
7 | -import javax.swing.JLabel; | ||
8 | import javax.swing.JPanel; | 6 | import javax.swing.JPanel; |
9 | 7 | ||
10 | public class Interface extends JFrame{ | 8 | public class Interface extends JFrame{ |
11 | private static final long serialVersionUID = 1L; | 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 | public Interface(MusicList musicList, final Runnable executeOnClose) { | 20 | public Interface(MusicList musicList, final Runnable executeOnClose) { |
19 | super("VRGNYMusicLights"); | 21 | super("VRGNYMusicLights"); |
@@ -22,6 +24,7 @@ public class Interface extends JFrame{ | @@ -22,6 +24,7 @@ public class Interface extends JFrame{ | ||
22 | populateWindow(); | 24 | populateWindow(); |
23 | pack(); | 25 | pack(); |
24 | setLocationRelativeTo(null); // center window | 26 | setLocationRelativeTo(null); // center window |
27 | + getContentPane().requestFocus(); | ||
25 | 28 | ||
26 | addWindowListener(new WindowAdapter() { | 29 | addWindowListener(new WindowAdapter() { |
27 | @Override | 30 | @Override |
@@ -35,34 +38,18 @@ public class Interface extends JFrame{ | @@ -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 | private void populateWindow() { | 47 | private void populateWindow() { |
39 | JPanel mainPanel = new JPanel(new BorderLayout()); | 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 | add(mainPanel); | 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,6 +3,6 @@ public class InvalidPatternException extends RuntimeException { | ||
3 | private static final long serialVersionUID = 1L; | 3 | private static final long serialVersionUID = 1L; |
4 | 4 | ||
5 | public InvalidPatternException() { | 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,6 +2,7 @@ import javax.swing.JOptionPane; | ||
2 | 2 | ||
3 | /* TODO list : | 3 | /* TODO list : |
4 | * - keyboard listener for animation player (play / pause = space, forward = semicolon, backward = comma, stop = backspace) | 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 | public class Main { | 7 | public class Main { |
7 | public static void main(String[] args) throws InterruptedException { | 8 | public static void main(String[] args) throws InterruptedException { |
@@ -22,8 +23,13 @@ public class Main { | @@ -22,8 +23,13 @@ public class Main { | ||
22 | MusicList musicList = new MusicList(null); | 23 | MusicList musicList = new MusicList(null); |
23 | musicList.addMusic( | 24 | musicList.addMusic( |
24 | new Music( | 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 | 1)); | 33 | 1)); |
28 | 34 | ||
29 | Interface i = new Interface(musicList, new Runnable() { | 35 | Interface i = new Interface(musicList, new Runnable() { |
VRGNYMusicLights/Sources/Music.java
@@ -10,6 +10,8 @@ public class Music { | @@ -10,6 +10,8 @@ public class Music { | ||
10 | this.volume = volume; | 10 | this.volume = volume; |
11 | } | 11 | } |
12 | 12 | ||
13 | + public MusicPattern getMusicPattern() { return pattern; } | ||
14 | + | ||
13 | public double[] render(long tick) { | 15 | public double[] render(long tick) { |
14 | double[] lights = new double[lightTickDelais.length]; | 16 | double[] lights = new double[lightTickDelais.length]; |
15 | for(int i=0; i<lights.length; i++) | 17 | for(int i=0; i<lights.length; i++) |
VRGNYMusicLights/Sources/MusicList.java
@@ -9,6 +9,7 @@ public class MusicList { | @@ -9,6 +9,7 @@ public class MusicList { | ||
9 | musics = new ArrayList<>(); | 9 | musics = new ArrayList<>(); |
10 | } | 10 | } |
11 | 11 | ||
12 | + public ArrayList<Music> getList() { return musics; } | ||
12 | public void addMusic(Music music) { musics.add(music); } | 13 | public void addMusic(Music music) { musics.add(music); } |
13 | public void deleteMusic(int index) { musics.remove(index); } | 14 | public void deleteMusic(int index) { musics.remove(index); } |
14 | 15 |
VRGNYMusicLights/Sources/MusicPath.java
@@ -75,34 +75,34 @@ public class MusicPath { | @@ -75,34 +75,34 @@ public class MusicPath { | ||
75 | || animation == CENTER_IN) { | 75 | || animation == CENTER_IN) { |
76 | switch (animation) { | 76 | switch (animation) { |
77 | case VERTICAL_DOWN: | 77 | case VERTICAL_DOWN: |
78 | - ticksDelais[i] += tickLateVerticalDown(LIGHT_COORDS[i][1]); | 78 | + ticksDelais[i] -= tickLateVerticalDown(LIGHT_COORDS[i][1]); |
79 | break; | 79 | break; |
80 | case VERTICAL_UP: | 80 | case VERTICAL_UP: |
81 | - ticksDelais[i] += tickLateVerticalUp(LIGHT_COORDS[i][1]); | 81 | + ticksDelais[i] -= tickLateVerticalUp(LIGHT_COORDS[i][1]); |
82 | break; | 82 | break; |
83 | case HORIZONTAL_TO_LEFT: | 83 | case HORIZONTAL_TO_LEFT: |
84 | - ticksDelais[i] += tickLateHorizontalToLeft(LIGHT_COORDS[i][0]); | 84 | + ticksDelais[i] -= tickLateHorizontalToLeft(LIGHT_COORDS[i][0]); |
85 | break; | 85 | break; |
86 | case HORIZONTAL_TO_RIGHT: | 86 | case HORIZONTAL_TO_RIGHT: |
87 | - ticksDelais[i] += tickLateHorizontalToRight(LIGHT_COORDS[i][0]); | 87 | + ticksDelais[i] -= tickLateHorizontalToRight(LIGHT_COORDS[i][0]); |
88 | break; | 88 | break; |
89 | case DIAGONAL_TOP_RIGHT_DOWN_LEFT: | 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 | break; | 91 | break; |
92 | case DIAGONAL_DOWN_LEFT_TOP_RIGHT: | 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 | break; | 94 | break; |
95 | case DIAGONAL_TOP_LEFT_DOWN_RIGHT: | 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 | break; | 97 | break; |
98 | case DIAGONAL_DOWN_RIGHT_TOP_LEFT: | 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 | break; | 100 | break; |
101 | case CENTER_OUT: | 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 | break; | 103 | break; |
104 | case CENTER_IN: | 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 | break; | 106 | break; |
107 | } | 107 | } |
108 | } | 108 | } |
@@ -111,16 +111,16 @@ public class MusicPath { | @@ -111,16 +111,16 @@ public class MusicPath { | ||
111 | return ticksDelais; | 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 | public int getNumberOfLights() { | 125 | public int getNumberOfLights() { |
126 | return this.lightsCoords.length; | 126 | return this.lightsCoords.length; |
VRGNYMusicLights/Sources/MusicPattern.java
@@ -5,37 +5,48 @@ public class MusicPattern { | @@ -5,37 +5,48 @@ public class MusicPattern { | ||
5 | * 1 : rise time | 5 | * 1 : rise time |
6 | * 2 : high time | 6 | * 2 : high time |
7 | * 3 : fall time | 7 | * 3 : fall time |
8 | + * 4 : low time | ||
8 | */ | 9 | */ |
9 | private int[] pattern; // in ms | 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 | private long begin; // in ms | 13 | private long begin; // in ms |
13 | private long stop; // in ms | 14 | private long stop; // in ms |
15 | + private int repeat; | ||
14 | 16 | ||
15 | public MusicPattern(int[] pattern, int repeat, long begin) { | 17 | public MusicPattern(int[] pattern, int repeat, long begin) { |
16 | - if(pattern.length != 4) | 18 | + if(pattern.length != 5) |
17 | throw new InvalidPatternException(); | 19 | throw new InvalidPatternException(); |
18 | this.pattern = pattern; | 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 | this.patternTiming[0] = pattern[0]; | 22 | this.patternTiming[0] = pattern[0]; |
21 | - for(int i=1; i<4; i++) | 23 | + for(int i=1; i<5; i++) |
22 | this.patternTiming[i] = this.patternTiming[i-1] + pattern[i]; | 24 | this.patternTiming[i] = this.patternTiming[i-1] + pattern[i]; |
23 | this.begin = begin; | 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 | public double render(long tick) { // tick in ms | 36 | public double render(long tick) { // tick in ms |
28 | if(tick <= begin) | 37 | if(tick <= begin) |
29 | return 0; | 38 | return 0; |
30 | if(tick >= stop) | 39 | if(tick >= stop) |
31 | return 0; | 40 | return 0; |
32 | - int tickMod = (int) (tick % totalLentgh); | 41 | + int tickMod = (int) (tick % totalLength); |
33 | if(tickMod < patternTiming[0]) | 42 | if(tickMod < patternTiming[0]) |
34 | return 0; | 43 | return 0; |
35 | if(tickMod < patternTiming[1]) | 44 | if(tickMod < patternTiming[1]) |
36 | return (double) (tickMod - patternTiming[0]) / (double) (pattern[1]); | 45 | return (double) (tickMod - patternTiming[0]) / (double) (pattern[1]); |
37 | if(tickMod < patternTiming[2]) | 46 | if(tickMod < patternTiming[2]) |
38 | return 1; | 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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 | +} |