////////////////////////////////////////////////////////////////////////////////
// Copyright 2012 Michael Schmalle - Teoti Graphix, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
//
// Author: Michael Schmalle, Principal Architect
// mschmalle at teotigraphix dot com
////////////////////////////////////////////////////////////////////////////////
package com.teotigraphix.caustk.project;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.androidtransfuse.event.EventObserver;
import com.teotigraphix.caustic.core.CausticException;
import com.teotigraphix.caustk.controller.ICaustkController;
import com.teotigraphix.caustk.controller.ISerialize;
import com.teotigraphix.caustk.library.vo.EffectRackInfo;
import com.teotigraphix.caustk.library.vo.MixerPanelInfo;
import com.teotigraphix.caustk.library.vo.RackInfo;
import com.teotigraphix.caustk.project.Track.OnTrackPhraseAdd;
import com.teotigraphix.caustk.project.Track.OnTrackPhraseRemove;
/**
* @author Michael Schmalle
* @copyright Teoti Graphix, LLC
* @since 1.0
*/
public class TrackSong extends Song implements ISerialize {
private transient ICaustkController controller;
public final ICaustkController getController() {
return controller;
}
public final void setController(ICaustkController value) {
controller = value;
}
//--------------------------------------------------------------------------
//
// ITrackSong API :: Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// rackInfo
//----------------------------------
private RackInfo rackInfo;
public RackInfo getRackInfo() {
return rackInfo;
}
public void setRackInfo(RackInfo value) {
rackInfo = value;
}
//----------------------------------
// mixerInfo
//----------------------------------
private MixerPanelInfo mixerInfo;
public MixerPanelInfo getMixerInfo() {
return mixerInfo;
}
public void setMixerInfo(MixerPanelInfo value) {
mixerInfo = value;
}
//----------------------------------
// effectRackInfo
//----------------------------------
private EffectRackInfo effectRackInfo;
public EffectRackInfo getEffectRackInfo() {
return effectRackInfo;
}
public void setEffectRackInfo(EffectRackInfo value) {
effectRackInfo = value;
}
//----------------------------------
// file
//----------------------------------
private File file;
/**
* Returns the relative song file path from the base <code>songs</code>
* directory.
* <p>
* Use the {@link ISongManager} to create an absolute file path for this
* song.
*/
public final File getFile() {
return file;
}
public final void setFile(File value) {
file = value;
}
//----------------------------------
// tracks
//----------------------------------
private int numTracks = -1;
public int getNumTracks() {
return numTracks;
}
/**
* Resets the number of {@link Track}s int he song.
* <p>
* Setting this property will reset all data and tracks.
*
* @param value The number of tracks in the song.
*/
public void setNumTracks(int value) {
numTracks = value;
createTracks();
initializeTracks();
}
private void createTracks() {
tracks.clear();
for (int i = 0; i < numTracks; i++) {
Track track = new Track();
track.setIndex(i);
tracks.put(i, track);
}
}
/**
* Initializes the {@link Track} instance.
* <p>
* Must be called after a {@link TrackSong} deserialization.
*/
public void initializeTracks() {
for (Track track : tracks.values()) {
track.setDispatcher(getDispatcher());
getDispatcher().register(OnTrackPhraseAdd.class, onTrackPhraseHandler);
getDispatcher().register(OnTrackPhraseRemove.class, onTrackPhraseRemoveHandler);
}
}
private transient EventObserver<OnTrackPhraseAdd> onTrackPhraseHandler = new EventObserver<OnTrackPhraseAdd>() {
@Override
public void trigger(OnTrackPhraseAdd object) {
Track track = object.getTrack();
TrackItem trackItem = object.getItem();
// IMachine machine = controller.getSoundSource().getTone(track.getIndex()).getMachine();
// int bank = trackItem.getBankIndex();
// int pattern = trackItem.getPatternIndex();
// int start = trackItem.getStartMeasure();
// int end = trackItem.getEndMeasure();
// // add the track to the song sequencer
// controller.getSystemSequencer().addPattern(machine, bank, pattern, start, end);
}
};
private transient EventObserver<OnTrackPhraseRemove> onTrackPhraseRemoveHandler = new EventObserver<OnTrackPhraseRemove>() {
@Override
public void trigger(OnTrackPhraseRemove object) {
Track track = object.getTrack();
TrackItem trackItem = object.getItem();
// IMachine machine = controller.getSoundSource().getTone(track.getIndex()).getMachine();
// int start = trackItem.getStartMeasure();
// int end = trackItem.getEndMeasure();
// // remove the track to the song sequencer
// controller.getSystemSequencer().removePattern(machine, start, end);
}
};
//----------------------------------
// tracks
//----------------------------------
private Map<Integer, Track> tracks = new HashMap<Integer, Track>();
/*
* The last pattern in the song in All tracks. This is used to easily
* calculate the measure length of the song.
*/
private TrackItem lastPatternInTracks;
public Collection<Track> getTracks() {
return Collections.unmodifiableCollection(tracks.values());
}
@Override
public int getNumBeats() {
if (lastPatternInTracks == null)
return 0;
int measures = lastPatternInTracks.getEndMeasure();
return measures * 4;
}
@Override
public int getNumMeasures() {
if (lastPatternInTracks == null)
return 0;
// 0 index, we need to use the end measure that is measures + 1
int measures = lastPatternInTracks.getEndMeasure();
return measures;
}
@Override
public int getTotalTime() {
float bpm = getBPM();
float timeInSec = 60 / bpm;
float totalNumBeats = getNumBeats() + getMeasureBeat();
float total = timeInSec * totalNumBeats;
return (int)total;
}
@Override
public int getCurrentTime() {
float bpm = getBPM();
float timeInSec = 60 / bpm;
float totalNumBeats = (getCurrentMeasure() * 4) + getMeasureBeat();
float total = timeInSec * totalNumBeats;
return (int)total;
}
public TrackSong() {
super();
}
/**
* Returns the {@link Track} at the specified index.
*
* @param index The tack index.
*/
public Track getTrack(int index) {
return tracks.get(index);
}
/**
* Clears all the tracks {@link TrackPhrase}s.
*
* @throws CausticException
*/
public void clearTracks() throws CausticException {
for (Track track : tracks.values()) {
track.clearPhrases();
}
}
@Override
public void sleep() {
TrackUtils.refreshTrackSongInfos(controller, this);
for (Track track : tracks.values()) {
track.sleep();
}
}
@Override
public void wakeup(ICaustkController controller) {
initializeTracks();
for (Track track : tracks.values()) {
track.wakeup(controller);
}
}
}
/*
RackInfo
<?xml version="1.0" encoding="UTF-8"?>
<rack>
<machine active="1" id="LOWLEAD" index="0" patchId="56c054c8-1dab-449c-89d6-d31249e9dddc" type="subsynth"/>
<machine active="1" id="HIGHLEAD" index="1" patchId="c3c71220-68bd-457d-8f95-f2af0fda4b6e" type="subsynth"/>
<machine active="1" id="BASS" index="2" patchId="ba868cf2-ef6d-49b2-a10f-591c1d853a9c" type="subsynth"/>
<machine active="1" id="MELODY" index="3" patchId="0e3932e8-301e-4aa1-a7e8-865935e7f46e" type="bassline"/>
<machine active="1" id="STRINGS" index="4" patchId="dbc19f2a-5bc6-426b-bff0-76b6efd184ea" type="pcmsynth"/>
<machine active="1" id="DRUMSIES" index="5" patchId="a146b131-d14d-4828-97b0-369c1accfa2d" type="beatbox"/>
</rack>
MixerInfo
<?xml version="1.0" encoding="UTF-8"?>
<mixer>
<master eq_bass="0.19565237" eq_high="0.100000024" eq_mid="0.0" id="-1" index="-1" volume="1.1478264"/>
<channels>
<channel delay_send="0.504348" eq_bass="-0.008696437" eq_high="0.06956482" eq_mid="1.1920929E-7" id="0" index="0" mute="0" pan="0.0" reverb_send="0.05869567" solo="0" stereo_width="0.99609375" volume="1.2782611"/>
<channel delay_send="0.5000001" eq_bass="-1.0" eq_high="0.02666676" eq_mid="0.034783125" id="1" index="1" mute="0" pan="0.0" reverb_send="0.0" solo="0" stereo_width="0.0" volume="1.3652176"/>
<channel delay_send="0.0" eq_bass="1.0" eq_high="-0.008695722" eq_mid="0.0" id="2" index="2" mute="0" pan="0.0" reverb_send="0.0" solo="0" stereo_width="0.0" volume="1.2782608"/>
<channel delay_send="0.52173936" eq_bass="-1.0" eq_high="-2.9802322E-7" eq_mid="-0.026086628" id="3" index="3" mute="0" pan="0.18260896" reverb_send="0.07173912" solo="0" stereo_width="0.0" volume="1.4383385"/>
<channel delay_send="0.0" eq_bass="-0.017391145" eq_high="0.38260782" eq_mid="0.0" id="4" index="4" mute="0" pan="0.0" reverb_send="0.07391316" solo="0" stereo_width="0.53269273" volume="1.3913045"/>
<channel delay_send="0.0" eq_bass="1.0" eq_high="5.9604645E-7" eq_mid="-0.008694708" id="5" index="5" mute="0" pan="0.0" reverb_send="0.0" solo="0" stereo_width="0.99609375" volume="0.99999934"/>
</channels>
<delay feedback="0.7565215" stereo="1" time="5"/>
<reverb damping="0.0" room="0.9" stereo="1"/>
</mixer>
*/