Skip to content

Commit

Permalink
Suffixes for cue numbers, basic cue lists, and more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nlowe committed Dec 2, 2016
1 parent 6ecec46 commit 026a8a8
Show file tree
Hide file tree
Showing 10 changed files with 682 additions and 27 deletions.
13 changes: 7 additions & 6 deletions Soundclip.Core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@

<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>2.0.2-beta</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
156 changes: 156 additions & 0 deletions Soundclip.Core/src/main/java/soundclip/core/CueList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// Copyright (C) 2016 Nathan Lowe
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package soundclip.core;

import soundclip.core.interop.Signal;

import java.util.*;

/**
* A named, ordered, collection of cues
*/
public class CueList implements Iterable<ICue>
{
private String name;
private final TreeMap<CueNumber, ICue> cues;

/** A signal that is triggered when the name of the cue list changes */
public final Signal<String> onNameChanged = new Signal<>();
/** A signal that is triggered when a cue is added to the list */
public final Signal<ICue> onCueAdded = new Signal<>();
/** A signal that is triggered when a cue is removed from the list */
public final Signal<ICue> onCueRemoved = new Signal<>();

/** A wrapper iterator to iterate over all cues in the list in order */
private class CueListIterator implements Iterator<ICue>
{
private final Iterator<java.util.Map.Entry<CueNumber, ICue>> entrySetIterator;

CueListIterator(Iterator<java.util.Map.Entry<CueNumber, ICue>> entrySetIterator)
{
this.entrySetIterator = entrySetIterator;
}

@Override
public boolean hasNext()
{
return entrySetIterator.hasNext();
}

@Override
public ICue next()
{
return entrySetIterator.next().getValue();
}
}

protected CueList()
{
cues = new TreeMap<>();
name = "Untitled Cue List";
}

protected CueList(String name)
{
this();
this.name = name;
}

protected CueList(Set<ICue> cues)
{
this();
for(ICue c : cues)
{
this.cues.put(c.getNumber(), c);
}
}

protected CueList(String name, Set<ICue> cues)
{
this();
for(ICue c : cues)
{
this.cues.put(c.getNumber(), c);
}
this.name = name;
}

/**
* Adds the cue to the cue list. If a cue with the same number exists in the list,
* the newly added cue will be suffixed with ".5"
*
* @param cue the cue to insert
*/
public void add(ICue cue)
{
// Append .5 to the number if the cue number already exists in the list
if(cues.containsKey(cue.getNumber())) cue.setNumber(new CueNumber(cue.getNumber(), 5));

cues.put(cue.getNumber(), cue);

onCueAdded.post(cue);
}

/**
* Remove the specified cue from the cue list
*
* @param cue
*/
public void remove(ICue cue)
{
remove(cue.getNumber());
}

/**
* Remove the cue specified by the provided number from the cue list
*
* @param cue
*/
public void remove(CueNumber cue)
{
ICue removed = cues.remove(cue);

if(removed != null)
{
onCueRemoved.post(removed);
}
}

/** @return the name of the Cue List */
public String getName()
{
return name;
}

/** Sets the name of the cue list */
public void setName(String name)
{
this.name = name;

onNameChanged.post(name);
}

/** @return the number of cues in the list */
public int size()
{
return cues.size();
}

@Override
public Iterator<ICue> iterator()
{
return new CueListIterator(cues.entrySet().iterator());
}
}
116 changes: 102 additions & 14 deletions Soundclip.Core/src/main/java/soundclip/core/CueNumber.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,55 +15,143 @@
package soundclip.core;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
* Cue Numbers are comprised of one or more non-negative integers separated by a dot (".").
*
* The most significant part is the leftmost part. Therefore, 1.0.1 < 1.0 and so on.
*/
public class CueNumber implements Comparable<CueNumber>
{
private final ArrayList<Integer> parts;
private final String toString;

/**
* Construct a Cue Number from the specified integers. The 0th integer
* is the most significant. The first part must be nonzero.
*
* @param fromInts the parts of the number
*/
public CueNumber(int...fromInts)
{
parts = new ArrayList<>(fromInts.length);

for(int i : fromInts)
{
if(i < 0) throw new IllegalArgumentException("All parts must be positive");
parts.add(i);
}

private CueNumber()
for(int i = parts.size() - 1; i >= 0; i--)
{
if(parts.get(i) != 0) break;

parts.remove(i);
}

if(parts.size() == 0) throw new IllegalArgumentException("No number provided");
toString = parts.stream().map(Object::toString).collect(Collectors.joining("."));
}

/**
* Construct a cue number from the specified string. The string should be comprised of
* only non-negative integers separated by a dot. The first part must be nonzero.
*
* @param fromString the string to create the number from
*/
public CueNumber(String fromString)
{
parts = new ArrayList<>();
if(fromString.trim().isEmpty()) throw new IllegalArgumentException("No number provided");

String[] stringParts = fromString.split("\\.");
parts = new ArrayList<>(stringParts.length);

for(String s : stringParts)
{
int i = Integer.parseInt(s);

if(i < 0) throw new IllegalArgumentException("All parts must be positive");
parts.add(i);
}

for(int i = this.parts.size() - 1; i >= 0; i--)
{
if(this.parts.get(i) != 0) break;

this.parts.remove(i);
}

if(parts.size() == 0) throw new IllegalArgumentException("No number provided");
toString = parts.stream().map(Object::toString).collect(Collectors.joining("."));
}

public CueNumber(int...parts)
/**
* Construct a new CueNumber prefixed by that of the specified number
*
* @param prefix the prefix of the newly constructed cue
* @param suffix the suffix to append
*/
public CueNumber(CueNumber prefix, int...suffix)
{
this();
if(suffix.length == 0) throw new IllegalArgumentException("No suffix provided");

parts = new ArrayList<>(prefix.parts.size() + suffix.length);
parts.addAll(prefix.parts);

for(int i : parts)
for(int i : suffix)
{
if(i < 0) throw new IllegalArgumentException("All parts must be positive");
this.parts.add(i);
parts.add(i);
}

if(this.parts.size() == 0) throw new IllegalArgumentException("No number provided");
for(int i = parts.size() - 1; i >= 0; i--)
{
if(parts.get(i) != 0) break;

parts.remove(i);
}

toString = parts.stream().map(Object::toString).collect(Collectors.joining("."));
}

public CueNumber(String fromString)
/**
* Construct a new CueNumber prefixed by that of the specified number. The suffix should be comprised of
* only non-negative integers separated by a dot.
*
* @param prefix the prefix of the newly constructed cue
* @param suffix the suffix to append
*/
public CueNumber(CueNumber prefix, String suffix)
{
this();
if(suffix.length() == 0) throw new IllegalArgumentException("No suffix provided");

if(fromString.trim().isEmpty()) throw new IllegalArgumentException("No number provided");
String[] stringParts = suffix.split("\\.");
parts = new ArrayList<>(prefix.parts.size() + stringParts.length);
parts.addAll(prefix.parts);

for(String s : fromString.split("\\."))
for(String s : stringParts)
{
int i = Integer.parseInt(s);

if(i < 0) throw new IllegalArgumentException("All parts must be positive");
parts.add(i);
}

if(parts.size() == 0) throw new IllegalArgumentException("No number provided");
for(int i = this.parts.size() - 1; i >= 0; i--)
{
if(this.parts.get(i) != 0) break;

this.parts.remove(i);
}

toString = parts.stream().map(Object::toString).collect(Collectors.joining("."));
}

@Override
public String toString()
{
return parts.stream().map(Object::toString).collect(Collectors.joining("."));
return toString;
}

@Override
Expand Down
22 changes: 18 additions & 4 deletions Soundclip.Core/src/main/java/soundclip/core/CueSupportFlags.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,28 @@
package soundclip.core;

/**
*
* Various flags to detect what features that different cue implementations support
*/
public class CueSupportFlags
{
public static int RESUME = 0b1;
public static int FADE = 0b10;

public boolean Supports(ICue cue, int flag)
/** Indicates that the cue implementation supports pausing and resuming */
public static final int RESUME = 0b001;
/** Indicates that the cue implementation supports fading in */
public static final int FADE_IN = 0b010;
/** Indicates that the cue implementation supports fading out */
public static final int FADE_OUT = 0b100;
/** Indicates that the cue implementation supports fading in both directions */
public static final int FADE = FADE_IN | FADE_OUT;

/**
* Determines if the specified feature is supported by the implementation of the specified cue
*
* @param cue The cue to inspect
* @param flag The flag to check
* @return {@code true} iff the cue implementation indicates that the specified feature is supported
*/
public static boolean Supports(ICue cue, int flag)
{
return (cue.getSupportedOperations() & flag) == flag;
}
Expand Down
10 changes: 10 additions & 0 deletions Soundclip.Core/src/main/java/soundclip/core/ICue.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@
*/
public interface ICue
{
/** @return the number of the cue */
CueNumber getNumber();
/** Set the number of the cue */
void setNumber(CueNumber number);

/** @return the name of the cue */
String getName();
/** Set the name of the cue */
void setName(String name);

/** @return the duration of the cue */
Duration getDuration();

/** @return the features supported by the cue. One or more of {@link CueSupportFlags} */
int getSupportedOperations();
}
Loading

0 comments on commit 026a8a8

Please sign in to comment.