001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030/** 031 * 032 */ 033package org.openimaj.audio.filters; 034 035import org.openimaj.audio.SampleChunk; 036import org.openimaj.audio.processor.FixedSizeSampleAudioProcessor; 037import org.openimaj.audio.samples.SampleBuffer; 038 039/** 040 * A basic feed-forward comb filter. A buffer is used to buffer the samples during the 041 * overlap of the sample chunks and it is initialised lazily, so the first 042 * time through the filter will take slightly longer. This filter extends the 043 * {@link FixedSizeSampleAudioProcessor} to ensure that the sample chunks are 044 * the same length as the required delay; this means that the buffer need only 045 * be copied in between each iteration. 046 * 047 * @author David Dupplaw (dpd@ecs.soton.ac.uk) 048 * @created 27 Apr 2012 049 * 050 */ 051public class FeedForwardCombFilter extends FixedSizeSampleAudioProcessor 052{ 053 /** The sample buffer that is used for dealing with the overlap sample chunks */ 054 private SampleBuffer buffer = null; 055 056 /** The gain of the delayed signal */ 057 private double gain = 1d; 058 059 /** The power of each frame of the output */ 060 private double outputPower = 0; 061 062 /** The power of each frame of the input */ 063 private double inputPower = 0; 064 065 /** The frequency being detected */ 066 private double frequency = 0; 067 068 /** 069 * Constructor that takes the number of samples delay 070 * to apply to the signal. 071 * 072 * @param nSamplesDelay The number of delay samples 073 * @param gain The gain of the delayed signal 074 */ 075 public FeedForwardCombFilter( final int nSamplesDelay, final double gain ) 076 { 077 super( nSamplesDelay ); 078 this.gain = gain; 079 this.frequency = -1; 080 } 081 082 /** 083 * Constructor that takes the frequency at which the comb filter 084 * will operate and the gain to apply to the delayed signal. 085 * 086 * @param frequency The frequency 087 * @param sampleRate The sample rate of the signal in Hz 088 * @param gain the gain of the delayed signal 089 */ 090 public FeedForwardCombFilter( final double frequency, final double sampleRate, final double gain ) 091 { 092 this( (int)(sampleRate/frequency), gain ); 093 this.frequency = frequency; 094 } 095 096 /** 097 * This returns the frequency that this comb filter is set to detect. 098 * This is only available if the frequency was used during construction. 099 * @return The frequency. 100 */ 101 public double getFrequency() 102 { 103 return this.frequency; 104 } 105 106 /** 107 * {@inheritDoc} 108 * @see org.openimaj.audio.processor.AudioProcessor#process(org.openimaj.audio.SampleChunk) 109 */ 110 @Override 111 public SampleChunk process( final SampleChunk sample ) throws Exception 112 { 113 // If we don't yet have a buffer, we must be at the start of 114 // the stream, so we pass the first samples on unedited and store 115 // them for the delayed signal. 116 if( this.buffer == null ) 117 { 118 this.buffer = sample.getSampleBuffer(); 119 return sample; 120 } 121 122 // Make a copy of the sample chunk and store it for later. 123 this.buffer = sample.clone().getSampleBuffer(); 124 125 // We'll side-affect the incoming chunk here 126 double p = 0; 127 double ip = 0; 128 final SampleBuffer b = sample.getSampleBuffer(); 129 for( int i = 0; i < b.size(); i++ ) 130 { 131 final float d = (float)(b.get(i) - this.gain*this.buffer.get(i)); 132 p += d*d; 133 ip += b.get(i) * b.get(i); 134 b.set( i, d ); 135 } 136 137 this.outputPower = p; 138 this.inputPower = ip; 139 140 // Return the incoming chunk, side-affected. 141 return sample; 142 } 143 144 /** 145 * Returns the output power for the last processed frame. 146 * @return the output power for the last processed frame. 147 */ 148 public double getOutputPower() 149 { 150 return this.outputPower; 151 } 152 153 /** 154 * Returns the input power for the last processed frame. 155 * @return the input power for the last processed frame. 156 */ 157 public double getInputPower() 158 { 159 return this.inputPower; 160 } 161 162 /** 163 * Returns the harmonicity power. 164 * @return the harmonicity power. 165 */ 166 public double getHarmonicity() 167 { 168 return this.getOutputPower() / (this.getInputPower()*4); 169 } 170}