package de.maramuse.soundcomp.effect;
/*
* 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 frequency shifter that changes the frequencies by adding a constant, exploiting trigonometric theorems
* The necessary 90 degrees shift of the input signal is carried out by an all pass filter approximating
* a Hilbert transform.
*/
import de.maramuse.soundcomp.filter.PseudoHilbert;
import de.maramuse.soundcomp.generator.Cosine;
import de.maramuse.soundcomp.process.NamedSource;
import de.maramuse.soundcomp.process.ParameterMap;
import de.maramuse.soundcomp.process.ProcessElement;
import de.maramuse.soundcomp.process.SourceStore;
import de.maramuse.soundcomp.process.StandardParameters;
import de.maramuse.soundcomp.process.Stateful;
import de.maramuse.soundcomp.process.TypeMismatchException;
import de.maramuse.soundcomp.process.UnknownConnectionException;
import de.maramuse.soundcomp.process.ValueType;
import de.maramuse.soundcomp.process.StandardParameters.Parameter;
import de.maramuse.soundcomp.util.ReadOnlyMap;
import de.maramuse.soundcomp.util.ReadOnlyMapImpl;
import de.maramuse.soundcomp.util.NativeObjects;
public class FreqShift implements ProcessElement, Stateful {
private static final ReadOnlyMapImpl<Integer, ValueType> srcMap=new ReadOnlyMapImpl<Integer, ValueType>();
private static final ReadOnlyMapImpl<Integer, ValueType> destMap=new ReadOnlyMapImpl<Integer, ValueType>();
private final ReadOnlyMapImpl<Integer, SourceStore> sourceMap=new ReadOnlyMapImpl<Integer, SourceStore>();
public long nativeSpace=-1;
public FreqShift() {
NativeObjects.registerNativeObject(this);
}
FreqShift(boolean s) {
}
private static ParameterMap inputsMap=new ParameterMap();
private static ParameterMap outputsMap=new ParameterMap();
static{
inputsMap.put(StandardParameters.FREQUENCY);
inputsMap.put(StandardParameters.IN);
outputsMap.put(StandardParameters.OUT);
outputsMap.put(StandardParameters.OUT_IMAG);
}
static{
srcMap.put(StandardParameters.OUT.i, ValueType.STREAM); // shifted up
srcMap.put(StandardParameters.OUT_IMAG.i, ValueType.STREAM); // shifted down
destMap.put(StandardParameters.IN.i, ValueType.STREAM);
destMap.put(StandardParameters.FREQUENCY.i, ValueType.STREAM);
}
private String abstractName=null, instanceName=null;
private SourceStore freq=null, in=null;
private PseudoHilbert ph=new PseudoHilbert();
private Cosine cos=new Cosine();
private double _val, val=0;
private double _valimag, valimag=0;
@Override
public ReadOnlyMap<Integer, ValueType> getSourceTypes() {
return srcMap;
}
@Override
public double getValue(int index) {
if(index==StandardParameters.OUT.i)
return val;
return valimag;
}
@Override
public void advanceOutput() {
val=_val;
valimag=_valimag;
}
@Override
public void advanceState() {
ph.advanceState();
cos.advanceState();
ph.advanceOutput();
cos.advanceOutput();
_val=ph.getValue(StandardParameters.OUT.i)
*cos.getValue(StandardParameters.OUT.i)
+ph.getValue(StandardParameters.OUT_IMAG.i)
*cos.getValue(StandardParameters.OUT_IMAG.i);
_valimag=ph.getValue(StandardParameters.OUT.i)
*cos.getValue(StandardParameters.OUT.i)
-ph.getValue(StandardParameters.OUT_IMAG.i)
*cos.getValue(StandardParameters.OUT_IMAG.i);
}
@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 ReadOnlyMap<Integer, ValueType> getDestinationTypes() {
return destMap;
}
@Override
public void setSource(int connectionIndex, NamedSource source,
int sourceIndex) throws UnknownConnectionException,
TypeMismatchException {
if(!source.getSourceTypes().containsKey(sourceIndex))
throw new UnknownConnectionException("attempt to set invalid source for FreqShift");
if(connectionIndex==StandardParameters.FREQUENCY.i){
freq=new SourceStore(source, sourceIndex);
cos.setSource(connectionIndex, source, sourceIndex);
sourceMap.put(StandardParameters.FREQUENCY.i, freq);
}else if(connectionIndex==StandardParameters.IN.i){
in=new SourceStore(source, sourceIndex);
ph.setSource(connectionIndex, source, sourceIndex);
sourceMap.put(StandardParameters.IN.i, in);
}else
throw new UnknownConnectionException("attempt to set unkown FreqShift parameter");
}
@Override
public long getNativeSpace() {
return nativeSpace;
}
public void cleanupSubObjects() {
NativeObjects.unregisterNativeObject(ph);
NativeObjects.unregisterNativeObject(cos);
}
/**
* @see de.maramuse.soundcomp.process.ProcessElement#clone()
*/
@Override
public FreqShift clone() {
FreqShift c=new FreqShift();
c.abstractName=abstractName;
return c;
}
@Override
public ReadOnlyMap<Integer, SourceStore> getSourceMap() {
return sourceMap;
}
/*
* (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;
}
}