diff src/uk/ac/qmul/eecs/depic/daw/Clip.java @ 0:3074a84ef81e

first import
author Fiore Martin <f.martin@qmul.ac.uk>
date Wed, 26 Aug 2015 16:16:53 +0100
parents
children 629262395647
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/uk/ac/qmul/eecs/depic/daw/Clip.java	Wed Aug 26 16:16:53 2015 +0100
@@ -0,0 +1,202 @@
+/*  
+ Cross-Modal DAW Prototype - Prototype of a simple Cross-Modal Digital Audio Workstation.
+
+ Copyright (C) 2015  Queen Mary University of London (http://depic.eecs.qmul.ac.uk/)
+	
+ 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 uk.ac.qmul.eecs.depic.daw;
+
+import uk.ac.qmul.eecs.depic.patterns.Range;
+
+
+public class Clip extends Range<Integer> implements Comparable<Clip> {
+	private Sample sample;
+	private int sampleStart;
+	private float startMs;
+	private float endMs;
+	private float millisecPerChunk;
+	private float sampleStartMs;
+	
+	public Clip(int start, int end, Sample sample, int sampleStart, float millisecPerChunk) {
+		super(start, end);
+		this.sample = sample;
+		this.sampleStart = sampleStart;
+		
+		this.millisecPerChunk = millisecPerChunk;
+		updateTimeMs();
+		sampleStartMs = sampleStart * millisecPerChunk;
+	}
+	
+	/**
+	 * 
+	 * Copy constructor
+	 * 
+	 * @param c another instance of {@code Clip}
+	 */
+	public Clip(Clip c){
+		this(c.start,c.end,c.sample,c.sampleStart,c.millisecPerChunk);
+	}
+
+	private void updateTimeMs(){
+		startMs = start * millisecPerChunk;
+		endMs = end * (millisecPerChunk) + millisecPerChunk;
+	}
+	
+	/**
+	 * Shifts the clips of the amount given as argument 
+	 * @param amount
+	 */
+	public void shift(int amount){
+		start += amount;
+		end = end += amount;
+		
+		updateTimeMs();
+	}
+	
+	public void setStartAt(int position){
+		int diff = position - start;
+		start = position;
+		end = end + diff;
+		
+		updateTimeMs();
+	}
+	
+	public Sample getSample() {
+		return sample;
+	}
+	
+	/**
+	 * Returns the chunks index where this selection starts relative to the start of the sample.
+	 * 
+	 * This is different from {@code getStart()}, as {@code getStart()} returns the 
+	 * absolute position (a.k.a. chunk index) of the selection start   
+	 * 
+	 * @return
+	 */
+	public int getSampleStart(){
+		return sampleStart;
+	}
+	
+	public float getSampleStartMs(){
+		return sampleStartMs;
+	}
+	
+	public float getStartTimeMs(){
+		return startMs;
+	}
+	
+	public float getEndTimeMs(){
+		return endMs;
+	}
+	
+	public float getMillisecPerChunk(){
+		return millisecPerChunk;
+	}
+	
+	/**
+	 * Checks whether {@code p} is contained in the selection,
+	 * that is greater than {@code getStart()} and lower than {@code getEnd()}.
+	 * 
+	 *  
+	 * @param p the integer value to check for 
+	 * @return {@code true} if {@code pos} is contained in the selection, {@code false} otherwise
+	 */
+	public boolean contains(int pos){
+		return ((pos>=getStart()) && (pos<=getEnd()));
+	}
+	
+	public boolean containsTime(float time){
+		return time >= startMs && time <= endMs;
+	}
+	
+	/**
+	 * Splits the selection around the given position.
+	 * 
+	 * If {@code pos} is less than the clip start or greater than the clip end, then the array will have size 1 and will
+	 * contain this Clip. Conversely if {@code pos} is contained in this clip an array with two new instances of {@code Clip} is returned. The clip at index 0, will range 
+	 * from {@code geStart()} to {@code pos-1}, whereas the clip at index 1 will range from {@code pos} to {@code getEnd()} 
+	 * 
+	 * 
+	 * @param pos the split position
+	 * @return an array of one or two clips, resulted from a split at position {@code pos}
+	 */
+	public Clip [] split(int pos){
+		/* if pos can go from start+1 to end                                    *
+		 * if pos == start+1, the split will be [start,start] and [start+1,end] *
+		 * if pos == end, the split will be [start,end-1] and [end,end]         */
+		if(pos <= getStart() || pos > getEnd()){ 
+			return new Clip [] {this};
+		}else{
+			return new Clip [] { 
+				new Clip(getStart(),pos-1,sample,sampleStart,millisecPerChunk),
+				new Clip(pos,getEnd(),sample,sampleStart+pos-getStart(),millisecPerChunk)
+			};
+		}
+	}
+	
+	@Override
+	public int compareTo(Clip s) {
+		return getStart().compareTo(s.getStart());
+	}
+
+	@Override
+	public String toString(){
+		return super.toString()+ ", selection in Ms:["+startMs+","+endMs+"], sample:"+ sample+ ", sample start:" +sampleStart;
+	}
+	
+	public static Clip join(Clip clip1, Clip clip2){
+		/* nulls not joinable */
+		if(clip1 == null || clip2 == null){
+			return null;
+		}
+		
+		/* clips with different sample or different resolution not joinable */
+		if(!clip1.sample.equals(clip2.sample) || clip1.millisecPerChunk != clip2.millisecPerChunk ){
+			return null;
+		}
+			
+		/* try clip2 after clip1 */
+		if(clip1.end+1 == clip2.start){
+			int clip1Len = clip1.end - clip1.start;
+			
+			if(clip1.sampleStart + clip1Len + 1 == clip2.sampleStart){
+				return new Clip(
+						clip1.start,
+						clip2.end,
+						clip1.sample,
+						clip1.sampleStart,
+						clip1.millisecPerChunk
+						);
+			}
+		/* try clip1 after clip2 */	
+		}else if(clip2.end+1 == clip1.start){
+			int clip2Len = clip2.end - clip2.start;
+			
+			if(clip2.sampleStart + clip2Len + 1 == clip2.sampleStart){
+				return new Clip(
+						clip2.start,
+						clip1.end,
+						clip2.sample,
+						clip2.sampleStart,
+						clip2.millisecPerChunk
+						);
+			}
+		}
+		
+		/* not joinable */
+		return null;
+	}
+	
+}