//Track class will hold a sequence of clips. Tracks will be //played simultaneously with other tracks. Volume will be //adjustable at a track level as well. // //Created by: Cam 3/30/13 //Adapted by: Mike 4/1/13 package com.teamluper.luper; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import android.os.Looper; import android.util.Log; import android.view.View; import com.androidlearner.widget.DragThing; public class Track { private SQLiteDataSource dataSource; // database field variables private long id; private long ownerUserID; private long parentSequenceID; private boolean isMuted; private boolean isLocked; private String playbackOptions; private boolean isDirty; // dirty = contains unsynced changes // what's going on with these?? DragThing deMovingTxt; int [] paramz; // references to related data public ArrayList<Clip> clips; public Clip nextClip; // references to any views depending on this data, so we can invalidate them automatically on set___ calls. public ArrayList<View> associatedViews = null; public TrackView trackView = null; // NOTE: DO NOT CALL THIS CONSTRUCTOR DIRECTLY unless in a cursorToTrack method. // instead, use SQLiteDataSource.createTrack()! public Track(SQLiteDataSource dataSource, long id, long ownerUserID, long parentSequenceID, boolean isMuted, boolean isLocked, String playbackOptions, boolean isDirty) { this.dataSource = dataSource; this.id = id; this.ownerUserID = ownerUserID; this.parentSequenceID = parentSequenceID; this.isMuted = isMuted; this.isLocked = isLocked; this.playbackOptions = playbackOptions; this.isDirty = isDirty; this.clips = new ArrayList<Clip>(); this.associatedViews = new ArrayList<View>(); this.nextClip = null; } public void addAssociatedView(View view) { this.associatedViews.add(view); if(TrackView.class.isInstance(view)) { this.trackView = (TrackView) view; } } public void removeAssociatedView(View view) { this.associatedViews.remove(view); } public ArrayList<View> getAssociatedViews() { return this.associatedViews; } public void invalidateAssociatedViews() { for(View v : this.associatedViews) { if(TrackView.class.isInstance(v)) { ((TrackView) v).render(); } v.requestLayout(); v.refreshDrawableState(); if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper()) { // we're in the main-thread / UI Thread. Log.i("luper", "INVALIDATE CALLING"); v.invalidate(); } else { // we're in a background thread. Log.i("luper", "POSTINVALIDATE CALLING"); v.postInvalidate(); } } } // temporary constructor for compatability with other files // TODO: WE NEED TO REMOVE THIS! public Track() { this.dataSource = null; } // Mike's getters and setters for database abstraction public long getId() { return id; } public void setId(long id) { long oldId = this.id; this.id = id; dataSource.updateLong("Tracks", oldId, "_id", id); invalidateAssociatedViews(); this.isDirty = true; } public long getOwnerUserID() { return ownerUserID; } public void setOwnerUserID(long ownerUserID) { this.ownerUserID = ownerUserID; dataSource.updateLong("Tracks", this.id, "ownerUserID", ownerUserID); invalidateAssociatedViews(); this.isDirty = true; } public long getParentSequenceID() { return parentSequenceID; } public void setParentSequenceID(long parentSequenceID) { this.parentSequenceID = parentSequenceID; dataSource.updateLong("Tracks", this.id, "parentSequenceID", parentSequenceID); invalidateAssociatedViews(); this.isDirty = true; } public boolean isMuted() { return isMuted; } public void setMuted(boolean isMuted) { this.isMuted = isMuted; dataSource.updateInt("Tracks", this.id, "isMuted", (isMuted ? 1 : 0)); invalidateAssociatedViews(); this.isDirty = true; } public boolean isLocked() { return isLocked; } public void setLocked(boolean isLocked) { this.isLocked = isLocked; dataSource.updateInt("Tracks", this.id, "isLocked", (isLocked ? 1 : 0)); invalidateAssociatedViews(); this.isDirty = true; } public String getPlaybackOptions() { return playbackOptions; } public void setPlaybackOptions(String playbackOptions) { this.playbackOptions = playbackOptions; dataSource.updateString("Tracks", this.id, "playbackOptions", playbackOptions); invalidateAssociatedViews(); this.isDirty = true; } public boolean isDirty() { return isDirty; } public void setDirty(boolean isDirty) { this.isDirty = isDirty; dataSource.updateInt("Tracks", this.id, "isDirty", (isDirty ? 1 : 0)); invalidateAssociatedViews(); } public void loadAllClipData() { this.clips = (ArrayList<Clip>) dataSource.getClipsByTrackId(this.id); for(Clip clip : this.clips) { clip.loadFileMetadata(); } } public void loadAllClipAudio() { if(this.clips == null) loadAllClipData(); for(Clip clip : this.clips) { clip.loadAudio(); } } public boolean prepareNextClip(int afterTimeMS) { // sort all clips by startTime Collections.sort(this.clips, new Comparator<Clip>() { public int compare(Clip a, Clip b) { return a.getStartTime() - b.getStartTime(); } }); // iterate through them and find the one following afterTimeMS Clip found = null; for(Clip c : this.clips) { if(c.getStartTime() > afterTimeMS) { found = c; break; } } if(found != null) { this.nextClip = found; this.trackView.prepareClip(this.nextClip); return true; } return false; } //SIZE public int size() { return clips.size(); } public ArrayList<Clip> getClips() { return this.clips; } //test methods public int findLargestClip() { int max=0, length; for(Clip c : clips) { length = c.getDurationMS()-c.getStartTime(); if(length>max) max=length; } return max; } public int findLastClipTime() { int temp = 0, last=0; for(Clip c : clips) { if(c!=null) { temp = c.getStartTime()+c.getDurationMS(); if(temp>last) last=temp; } else last = 100; } return last; } }