/* License see bottom */
package jpianotrain.staff;
import java.util.ArrayList;
import java.util.List;
import jpianotrain.event.TuneFactoryListener;
import jpianotrain.util.UserConfiguration;
import org.apache.log4j.Logger;
/**
* Use this class and it's static methods to get
* a tune factory. If you write new factories,
* provide access method here.
*
* @since 0
* @author Alexander Methke
*/
public abstract class TuneFactory {
private static final Logger log=Logger.getLogger(TuneFactory.class);
protected TuneFactory() {
listeners=new ArrayList<TuneFactoryListener>();
}
/**
* Creates the tune based on the
* information found in this
* factory.
*/
public Tune create() {
Tune t=new Tune();
t.setRightHand(createRightHand());
if (isBothHands()) {
t.setLeftHand(createLeftHand());
}
return t;
}
/**
* Keep factory from firing events.
* If you intend to change all settings
* like bounds for notes, then you must
* hold events. Every method invocation
* would raise an event thus updating the
* GUI (with wrong data). So hold events
* until you're finished, and flush when
* ready.
*
* @see #flushEvents()
*/
public void holdEvents() {
holdEvents=true;
}
/**
* Flush events. When you previously
* holded back events you must invoke
* this method to release all events from
* the past.
*
* @see #holdEvents()
*/
public void flushEvents() {
if (holdEvents==true) {
holdEvents=false;
}
if (settingsChanged) {
fireSettingsChanged();
settingsChanged=false;
}
}
/**
* Realize this method to return notes
* for the right hand. Pay attention to
* the parameters, set in this class.
* This method will always be called, when
* the GUI requests a new set of notes.
*/
protected abstract List<Note> createRightHand();
/**
* Realize this method to return
* notes for the left hand. Pay attention
* to the parameters, set in this class.
* This method will only be called, if the
* tune is for both hands.
*
* @see #isBothHands
*/
protected abstract List<Note> createLeftHand();
/**
* Returns the single random instance.
*/
public static TuneFactory getRandomFactory() {
return randomFactory;
}
/**
* Instead of getting all factories and registering
* yourself step by step you ought to use this
* method.
*
* @see #addListener
*/
public static void registerForAll(TuneFactoryListener l) {
getRandomFactory().addListener(l);
}
/**
* Instead of getting all factories and deregistering
* yourself step by step you ought to use this
* method.
*
* @see #removeListener
*/
public static void deregisterFromAll(TuneFactoryListener l) {
getRandomFactory().removeListener(l);
}
/**
* Invoke this method if you want the settings of all
* factories to be saved to user configuration. Normally
* this is done, if the application is shutting down,
* e.g. when main window is closing.
*/
public static void storeConfiguration() {
UserConfiguration uc=UserConfiguration.getInstance();
storeRandomConfig(uc);
storeMidiFileConfig(uc);
storeLessonConfig(uc);
}
private static void storeRandomConfig(UserConfiguration uc) {
randomFactory.store();
}
/**
*
* @todo Nothing to save yet.
* @param uc
*/
private static void storeLessonConfig(UserConfiguration uc) {
// nothing to save, yet
}
/**
*
* @todo Nothing to save yet.
* @param uc
*/
private static void storeMidiFileConfig(UserConfiguration uc) {
// nothing to save, yet
}
public void setScale(Scale s) {
if (scale==s) {
return;
}
scale=s;
fireSettingsChanged();
}
public Scale getScale() {
return scale;
}
public void setBothHands(boolean bh) {
if (bothHands==bh) {
return;
}
bothHands=bh;
fireSettingsChanged();
}
public boolean isBothHands() {
return bothHands;
}
public void setLowerBoundBass(int lbb) {
if (lowerBoundBass==lbb) {
return;
}
lowerBoundBass=lbb;
fireSettingsChanged();
}
public int getLowerBoundBass() {
return lowerBoundBass;
}
public void setUpperBoundBass(int ubb) {
if (upperBoundBass==ubb) {
return;
}
upperBoundBass=ubb;
fireSettingsChanged();
}
public int getUpperBoundBass() {
return upperBoundBass;
}
public void setLowerBoundTreble(int lbb) {
if (lowerBoundTreble==lbb) {
return;
}
lowerBoundTreble=lbb;
fireSettingsChanged();
}
public int getLowerBoundTreble() {
return lowerBoundTreble;
}
public void setUpperBoundTreble(int ubb) {
if (upperBoundTreble==ubb) {
return;
}
upperBoundTreble=ubb;
fireSettingsChanged();
}
public int getUpperBoundTreble() {
return upperBoundTreble;
}
public void setNoteCount(int count) {
if (noteCount==count) {
return;
}
noteCount=count;
fireSettingsChanged();
}
public int getNoteCount() {
return noteCount;
}
protected List<Note> getAllowedNotesBass() {
int lb=getLowerBoundBass();
int ub=getUpperBoundBass();
return getAllowedNotesInBound(lb, ub);
}
protected List<Note> getAllowedNotesTreble() {
int lb=getLowerBoundTreble();
int ub=getUpperBoundTreble();
return getAllowedNotesInBound(lb, ub);
}
private List<Note> getAllowedNotesInBound(int lower, int upper) {
log.debug("getAllowedNotesInBound("+lower+", "+upper+")");
Scale s=getScale();
log.debug("Scale: "+s);
List<Note> nl=getScale().getNotes();
int octave=(lower/12)-1;
List<Note> allowedNotes=new ArrayList<Note>();
for(int oct=octave;oct<octave+3;oct++) {
log.debug("running with octave "+oct);
for (Note n:nl) {
Note nn=new Note(Duration.WHOLE,
n.getName(),
oct*12);
log.debug("testing note "+nn);
if (nn.getPitch()<lower) {
log.debug("not yet above, continueing");
continue;
} else if (nn.getPitch()>upper) {
log.debug("already above, break");
break;
} else {
log.debug("found one, adding");
allowedNotes.add(nn);
}
}
}
return allowedNotes;
}
/**
* Adds the given listener but only if it
* wasn't registered before.
*
* @see #registerForAll
*/
public void addListener(TuneFactoryListener l) {
if (listeners.contains(l)) {
return;
}
listeners.add(l);
}
/**
* Removes the given listener.
*
* @see #deregisterFromAll
*/
public void removeListener(TuneFactoryListener l) {
listeners.remove(l);
}
protected void fireSettingsChanged() {
if (holdEvents) {
settingsChanged=true;
return;
}
for(TuneFactoryListener l:listeners) {
l.settingsChanged(this);
}
}
private static final RandomTuneFactory randomFactory=new RandomTuneFactory();
private boolean bothHands;
private boolean holdEvents;
private boolean settingsChanged;
private int noteCount;
private int lowerBoundBass;
private int upperBoundBass;
private int lowerBoundTreble;
private int upperBoundTreble;
private Scale scale;
private List<TuneFactoryListener> listeners;
}
/*
Copyright (C) 2008 Alexander Methke
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 (gplv3.txt).
*/