package de.maramuse.soundcomp.process;
/*
* Copyright 2010 Jan Schmidt-Reinisch
*
* SoundComp - a sound processing library
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; in version 2.1
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* A mono flop that is triggered by the TimerMap. The input stream supplies the current switch-on time.
* TODO: native counterpart. Needs no setter for state, only the value getter.
*/
import de.maramuse.soundcomp.process.StandardParameters.Parameter;
import de.maramuse.soundcomp.process.TimerMap.Event;
import de.maramuse.soundcomp.util.AdvancerRegistry;
import de.maramuse.soundcomp.util.ReadOnlyMap;
import de.maramuse.soundcomp.util.ReadOnlyMapImpl;
public class EventMonoFlop implements ProcessElement, Stateful {
private AdvancerRegistry advancerRegistry;
private String abstractName;
private String instanceName;
private long nativeSpace=-1L;
private boolean state=false;
private boolean state_int=false;
private NamedSource source=null;
private int sourceIndex=0;
private Event lastSwitchOffEvent=null;
private static final ReadOnlyMapImpl<Integer, ValueType> sourceTypes=new ReadOnlyMapImpl<Integer, ValueType>();
private static final ReadOnlyMapImpl<Integer, ValueType> destMap=new ReadOnlyMapImpl<Integer, ValueType>();
private static ParameterMap inputsMap=new ParameterMap();
private static ParameterMap outputsMap=new ParameterMap();
static{
inputsMap.put(StandardParameters.IN);
outputsMap.put(StandardParameters.OUT);
}
static{
sourceTypes.put(StandardParameters.OUT.i, ValueType.STREAM);
// the input is the duration in seconds. therefore we will not have to explicitly specify an end event from the
// outside
// this monoflop creates it on its own
destMap.put(StandardParameters.IN.i, ValueType.STREAM);
}
/* making this private to prevent creation of instances until the advancerRegistry
* propagation issue is defined
*/
private EventMonoFlop(){
}
public Event getOnEvent() {
return new Event() {
@Override
public void notifyElement(ProcessElement processElement) {
double d=0.0;
synchronized(EventMonoFlop.this){
if(lastSwitchOffEvent!=null)
advancerRegistry.removeEvent(lastSwitchOffEvent);
// determine the switch-off-time
if(source!=null)
d=source.getValue(sourceIndex);
// only do anything if the switch-off-time is in the future
if(d>0d){
EventMonoFlop.this.setOn();
// processElement is always the monoflop here
advancerRegistry.addEvent(advancerRegistry.currentTime()+d,
lastSwitchOffEvent=getOffEvent(),
EventMonoFlop.this);
}
}
}
};
}
public Event getOffEvent() {
return new Event() {
@Override
public void notifyElement(ProcessElement processElement) {
synchronized(EventMonoFlop.this){
// processElement is always the monoflop here
EventMonoFlop.this.setOff();
if(lastSwitchOffEvent==this)
lastSwitchOffEvent=null;
}
}
};
}
@Override
public ReadOnlyMap<Integer, ValueType> getDestinationTypes() {
return destMap;
}
@Override
public void setSource(int connectionIndex, NamedSource source,
int sourceIndex) throws UnknownConnectionException,
TypeMismatchException {
if(connectionIndex!=StandardParameters.IN.i)
throw new UnknownConnectionException("EventMonoFlop only has standard input");
if(source==null){
this.source=null;
state_int=false;
return;
}
ValueType vt=source.getSourceTypes().get(sourceIndex);
if(vt==null)
throw new UnknownConnectionException("EventMonoFlop failed to connect");
if(vt!=ValueType.DOUBLE&&vt!=ValueType.STREAM)
throw new TypeMismatchException();
this.source=source;
this.sourceIndex=sourceIndex;
}
@Override
public ReadOnlyMap<Integer, ValueType> getSourceTypes() {
return sourceTypes;
}
@Override
public double getValue(int index) {
return state ? 1d : 0d;
}
@Override
public void advanceOutput() {
state=state_int;
}
@Override
public void advanceState() {
// nothing to do
}
@Override
public String getAbstractName() {
return abstractName;
}
@Override
public String getInstanceName() {
return instanceName;
}
@Override
public void setAbstractName(String abstractName) {
this.abstractName=abstractName;
}
@Override
public void setInstanceName(String instanceName) {
this.instanceName=instanceName;
}
@Override
public long getNativeSpace() {
return nativeSpace;
}
@Override
public EventMonoFlop clone() {
EventMonoFlop n=new EventMonoFlop();
n.advancerRegistry=advancerRegistry;
n.state=state;
n.state_int=state_int;
return n;
}
private void setOn() {
state_int=true;
}
private void setOff() {
state_int=false;
}
@Override
public ReadOnlyMap<Integer, SourceStore> getSourceMap() {
return ReadOnlyMapImpl.emptyMapIntSource;
}
/*
* (non-Javadoc)
*
* @see de.maramuse.soundcomp.process.ProcessElement#outputsByName()
*/
@Override
public ReadOnlyMap<String, Parameter> outputsByName() {
return outputsMap;
}
/*
* (non-Javadoc)
*
* @see de.maramuse.soundcomp.process.ProcessElement#inputsByName()
*/
@Override
public ReadOnlyMap<String, Parameter> inputsByName() {
return inputsMap;
}
/**
* An event monoflop wants to register and unregister events. therefore, it needs
* access to the advancerRegistry of the current compilation (as this is no longer
* global).
* @param advancerRegistry the AdvancerRegistry of the current compilation
*/
public void setAdvancerRegistry(AdvancerRegistry advancerRegistry){
this.advancerRegistry=advancerRegistry;
}
}