Mercurial > hg > cmdp
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; + } + +}