-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSong.java
170 lines (145 loc) · 3.54 KB
/
Song.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package bettycrocker;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
* The Song class represents a collection of Tracks that are played
* synchronously to provide a final mix that is the song that is played.
*
* In order to create a song, you have two options:
* 1.) You can define a List of Tracks and initialize the Song with the List
* 2.) You can create a Song with the default constructor and add Tracks later
*
* Once a Song is created, the 'startPlaying' method needs to be called to
* start the Song, and the 'stopPlaying' method is called to stop it.
*
* @author John
*
*/
public class Song {
//Used for making sure the Tracks start at the same time
private final CountDownLatch startLatch = new CountDownLatch(1);
private List<Track> tracks;
private boolean isPlaying = false;
private boolean isLooping = false;
/**
* The default constructor for a Song. It simply initializes the list
* of Tracks to an empty list.
*/
public Song() {
tracks = new ArrayList<Track>();
}
/**
* Creates a Song and populates the list of Tracks with the given
* list of Tracks.
* @param tracks
*/
public Song(List<Track> tracks) {
for (Track track : tracks) {
addTrack(track);
}
}
/**
* Plays the Song with the current looping setting.
*/
public void startPlaying() {
startPlaying(isLooping);
}
/**
* Plays the Song, allowing the user to pass in the looping
* setting.
* @param loop
*/
public void startPlaying(boolean loop) {
isLooping = loop;
isPlaying = true;
new PlayThread().start();
}
/**
* Stops the Song.
*/
public void stopPlaying() {
isPlaying = false;
isLooping = false;
for(Track track : tracks) {
track.stopPlaying();
}
}
/**
* Adds a Track to the Song.
* @param track
*/
public void addTrack(Track track) {
insertTrack(tracks.size(), track);
}
/**
* Allows the user to add a Track to the Song at a specific
* index.
* @param index
* @param track
*/
public void insertTrack(int index, Track track) {
track.setStartLatch(startLatch);
tracks.add(index, track);
}
/*
* This method starts all of the Tracks assigned to this
* song at the same time.
*/
private void playTracks() {
for(Track track : tracks) {
track.startPlaying();
}
//Sleep for a short amount of time to give all of the tracks a chance to start playing
try {
Thread.sleep(200);
} catch (InterruptedException e) {
System.out.println("Problem sleeping before starting track playback.");
e.printStackTrace();
}
//Count down the start latch to have all tracks begin playing at the same time
startLatch.countDown();
}
/*
* Determines if all tracks are finished playing
*/
private boolean allTracksFinished() {
boolean allTracksFinished = true;
for (Track track : tracks) {
if (track.isPlaying()) {
allTracksFinished = false;
break;
}
}
return allTracksFinished;
}
/**
* Sets the looping setting.
* @param isLooping
*/
public void setLooping(boolean isLooping) {
this.isLooping = isLooping;
}
/**
* Gets the list of Tracks
* @return
*/
public List<Track> getTracks() {
return tracks;
}
/*
* This class is the thread that is used for playing the Tracks.
* It is needed so that main flow of the application is not
* interrupted while the Song plays.
*/
private class PlayThread extends Thread {
public void run() {
playTracks();
while (isPlaying && isLooping) {
if (allTracksFinished()) {
playTracks();
}
}
}
}
}