Package de.maramuse.soundcomp.effect

Source Code of de.maramuse.soundcomp.effect.Flanger

package de.maramuse.soundcomp.effect;

/*
* Copyright 2012 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 delay and equidistant comb filter effect suitable for enhancing the "livelyness" of otherwise
* static sounds. Overlaying the original with a short-delayed copy with variable delay time.
*
* Note that this element has a MAXDELAY input. Whilst the all other inputs are evaluated on the fly
* and changes on the other inputs during playing have influence on the effect, the MAXDELAY input
* is being read on initialization of the element only, and later changes to not have any effect.
* The MAXDELAY input is used for determining the memory reserved for the delay loop, which is never
* resized thereafter. It thus makes no sense to connect the MAXDELAY input to anything but a ConstStream.
* If unconnected, defaults to 1s.
*
* There are inputs for FREQUENCY and DEPTH of the modulation. If however the MODULATION input is connected,
* the internal LFO is disregarded, to allow connecting more versatile LFOs for modulation. It makes no
* sense to connect any sources to FREQUENCY and MODULATION at the same time, and MODULATION has precedence.
* DEPTH multiplies with either the MODULATION input or internal LFO output, then adds to the DELAY input to
* build the actual delay time. The DELAY input usually is meant to connect to a constant average delay that
* the LFO oder MODULATION input add to (but may be exploited for a second modulation source). Take care
* that the sum of MODULATION/LFO and DELAY is hard limited to 0<=sum<=MAXDELAY.
* As always, all time parameters are in seconds, frequency parameters in Hz, although MAXDELAY, DELAY and DEPTH
* will usually be in the 3-30ms range, and FREQUENCY something around 0.3Hz..3Hz.
*
* TODO anti alias filtering implementation missing (skipping and/or inserting samples by modulating delay
*     is a type of pitch shift/TDHS and would require anti aliasing filtering).
*     Feedback?
*/

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.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.GlobalParameters;
import de.maramuse.soundcomp.util.NativeObjects;
import de.maramuse.soundcomp.util.ReadOnlyMap;
import de.maramuse.soundcomp.util.ReadOnlyMapImpl;

public class Flanger implements ProcessElement {

  private String abstractName, instanceName;
  private long nativeSpace=-1;
  private boolean initialized=false;
  private double[] samples;
  private double out1=0.0, out2=0.0, _out1, _out2, lfophase=0.0, samplerate=0.0;
  int index;
  private SourceStore maxDelay=null, delay=null, frequency=null, in=null, depth=null,
    modulation=null, intensity=null;
  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>();
  private static ParameterMap inputsMap=new ParameterMap();
  private static ParameterMap outputsMap=new ParameterMap();
  static{
  inputsMap.put(StandardParameters.FREQUENCY); // the LFO frequency
  inputsMap.put(StandardParameters.DEPTH); // the LFO amplitude, in resulting delay seconds
  inputsMap.put(StandardParameters.INTENSITY); // the amount of delayed signal in the mix
  // if this input is connected, the internal LFO is disconnected, to allow for versatile modulation.
  // Expect an amplitude 1 signal here, -1 means no delay, +1 means MAXDELAY
  inputsMap.put(StandardParameters.DELAY);
  inputsMap.put(StandardParameters.MAXDELAY);
  inputsMap.put(StandardParameters.MODULATION);
  inputsMap.put(StandardParameters.IN);
  destMap.put(StandardParameters.FREQUENCY.i, ValueType.STREAM);
  destMap.put(StandardParameters.DEPTH.i, ValueType.STREAM);
  destMap.put(StandardParameters.INTENSITY.i, ValueType.STREAM);
  destMap.put(StandardParameters.DELAY.i, ValueType.STREAM);
  destMap.put(StandardParameters.MODULATION.i, ValueType.STREAM);
  destMap.put(StandardParameters.MAXDELAY.i, ValueType.DOUBLE);
  destMap.put(StandardParameters.IN.i, ValueType.STREAM);
  outputsMap.put(StandardParameters.OUT);
  outputsMap.put(StandardParameters.OUT_IMAG);
  srcMap.put(StandardParameters.OUT.i, ValueType.STREAM);
  srcMap.put(StandardParameters.OUT_IMAG.i, ValueType.STREAM);
  }

  public Flanger() {
  NativeObjects.registerNativeObject(this);
  }

  @Override
  public ReadOnlyMap<Integer, ValueType> getSourceTypes() {
  return srcMap;
  }

  @Override
  public double getValue(int _index) {
  if(_index==StandardParameters.OUT.i)
    return out1;
  else if(_index==StandardParameters.OUT_IMAG.i)
    return out2;
  else
    throw new IllegalArgumentException();
  }

  @Override
  public ReadOnlyMap<String, Parameter> outputsByName() {
  return outputsMap;
  }

  @Override
  public void advanceState() {
  double currval=in.getValue();
  if(!initialized){
    double memorySize=samplerate=GlobalParameters.get().getSampleRate();
    if(maxDelay!=null)
    memorySize*=maxDelay.getValue();
    samples=new double[(int)memorySize];
    initialized=true;
  }
  double _modulation=Double.NaN;
  if(modulation!=null)
    _modulation=modulation.getValue();
  else{
    lfophase+=frequency.getValue()/samplerate/2/Math.PI;
    lfophase%=1.0;
    _modulation=Math.cos(lfophase);
  }
  _modulation*=depth.getValue();
  double _delay=(delay.getValue()+_modulation)*samplerate;
  if(_delay<0)
    _delay=0;
  if(_delay>=samples.length)
    _delay=samples.length;
  double _intensity=1.0;
  if(intensity!=null)
    _intensity=intensity.getValue();
  _out1=currval+_intensity*samples[(int)((index+samples.length-_delay)%samples.length)];
  _out2=currval-_intensity*samples[(int)((index+samples.length-_delay)%samples.length)];
  index=index+1;
  if(index==samples.length)
    index=0;
  samples[index]=currval;
  }

  @Override
  public void advanceOutput() {
  out1=_out1;
  out2=_out2;
  }

  @Override
  public void setAbstractName(String abstractName) {
  this.abstractName=abstractName;
  }

  @Override
  public String getAbstractName() {
  return abstractName;
  }

  @Override
  public void setInstanceName(String instanceName) {
  this.instanceName=instanceName;
  }

  @Override
  public String getInstanceName() {
  return instanceName;
  }

  @Override
  public long getNativeSpace() {
  return nativeSpace;
  }

  @Override
  public ReadOnlyMap<Integer, ValueType> getDestinationTypes() {
  return destMap;
  }

  @Override
  public void setSource(int connectionIndex, NamedSource source, int sourceIndex)
    throws UnknownConnectionException, TypeMismatchException {
  if(connectionIndex==StandardParameters.MAXDELAY.i){
    // TODO check whether it's a constant?
    maxDelay=new SourceStore(source, sourceIndex);
  }else if(connectionIndex==StandardParameters.INTENSITY.i){
    intensity=new SourceStore(source, sourceIndex);
  }else if(connectionIndex==StandardParameters.FREQUENCY.i){
    frequency=new SourceStore(source, sourceIndex);
  }else if(connectionIndex==StandardParameters.DELAY.i){
    delay=new SourceStore(source, sourceIndex);
  }else if(connectionIndex==StandardParameters.DEPTH.i){
    depth=new SourceStore(source, sourceIndex);
  }else if(connectionIndex==StandardParameters.MODULATION.i){
    modulation=new SourceStore(source, sourceIndex);
  }else if(connectionIndex==StandardParameters.IN.i){
    in=new SourceStore(source, sourceIndex);
  }
  }

  @Override
  public ReadOnlyMap<Integer, SourceStore> getSourceMap() {
  return sourceMap;
  }

  @Override
  public ReadOnlyMap<String, Parameter> inputsByName() {
  return inputsMap;
  }

  /**
   * @see de.maramuse.soundcomp.process.ProcessElement#clone()
   */
  @Override
  public Flanger clone() {
  Flanger c=new Flanger();
  c.abstractName=abstractName;
  return c;
  }
}
TOP

Related Classes of de.maramuse.soundcomp.effect.Flanger

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.