developing a set of data filters which could be used for an application such as audio processing in java
Get perfect grades by consistently using our writing services. Place your order and get a quality paper today. Take advantage of our current 20% discount by using the coupon code GET20
Order a Similar Paper Order a Different Paper
- The objective of this project is to practice producing class hierarchies, by developing a set of data filters which could be used for an application such as audio processing. This project will involve using abstract classes and inheritance to create several related classes which share functionality.
Overview:
- Create the
abstract
classDataSource
, which allows data to be read one floating point number at a time. - Create three subclasses of
DataSource
, namelyArraySource
which draws its input from an array;SineSource
which produces a sine-wave output; andDataFilter
, which draws its input from anotherDataSource
. - Create subclass of
DataFilter
calledScaleFilter
, which scales (multiplies) the input by a constant; andSineScaleFilter
, which scales the input by a sine wave. - Create a subclass of
DataFilter
calledBufferedFilter
, which uses a circular buffer to remember a range of previous input. - Create a subclass of
BufferedFilter
calledEchoFilter
which echoes the input with a certain delay.
Audio processing typically involves taking streams of digital data – streams of discrete, oscillating numbers – and performing various mathematical operations on them. However, there are a number of different operations you can use to process an audio stream – from the simple, like amplitude scaling (increasing and decreasing the volume), to more complicated, like filters which isolate certain audio frequencies, to specialized ones which produce different audio effects. In this project, we will set up a framework for audio filtering, and produce a few basic filters.Rules
- You may not import any extra functionality besides the default (i.e. System, Math)
- The
main
method will not be tested; you may use it any way you want. - All fields must be declared
private
orprotected
. This will be verified manually. - You may write your own helper methods, but any methods which are specifically asked for must match exactly (i.e. capitalization of the method name; number and order of the parameters).
DataSource: ( 10p)
public abstract class DataSource implements java.util.Iterator
We can begin with a class that represents a generic source of data. The data we will be dealing with is a stream of
Double
data (remember thatDouble
is just the reference version of thedouble
primitive type). The data from the stream is to be read one floating point number at a time, for as long as there is data left on the stream. This class isabstract
– our data-reading methods are left there as a placeholder for future classes to override. The class should implement the following:public DataSource()
we don’t need to do anything at this point, but it’s still nice to have a constructor as a placeholder.@Override public abstract Double next();
this would pull the next unit of data from the stream; not implemented yet.@Override public abstract boolean hasNext();
this would tell us if there is more data left in the stream; not implemented yet.public void display()
whilehasNext()
indicates that there is more data left in this source,println
the result oftoString()
(hint: there’s nothing fancy about this method, and it can be written in as little as one line of code). The result will be a visual depiction of the data stream.@Override public String toString()
this pulls a value from the source usingnext()
and uses it to produce a text string containing a single asterisk surrounded by whitespace. Use the following code:@Override public String toString() {
double d = next();
if (d < -5 || d > 5) return "";
int i = (int)(7*d + 40);
return String.format("%" + i + "s", "*");
}
Notice how the class declares that it implements some kind of iterator? That’s something which we gained for free, just by ensuring that we gave our methods the right names.ArraySource: (10p)
public class ArraySource extends DataSource
We already have data sources which have no data! Let’s do something about that. This basic data source will allow you to enter an array ofDouble
values to use as input. Calls tonext()
will begin with the first value in the array, and continue in order until there are no more values in the array, at which pointhasNext()
will begin to returnfalse
. The only new method in this class will be the constructor, althoughnext()
andhasNext()
must be overriden so that the class is no longer abstract:public ArraySource(Double[] a)
initializes the source using the arraya
(assume that it’s notnull
.@Override public Double next()
.@Override public boolean hasNext()
.
SineSource: (10p)
public class SineSource extends DataSource
TheSineSource
is another source of data, but this time it generates its own data. As you may be able to guess from the name, it generates a sine wave. A sine wave has several parameters: the amplitudea
represents how large it is; the frequencyf
represents how quickly it oscillates; and the offsetd
represents the moment it begins. Together, they form an equation like the following:a×sin(f×t + d)
The variablet
above represents the time step: the first time you callnext()
corresponds to zero, the next time to 1, etc. Assume that the angle is in radians, to be consistent with Java’s built inMath
functionality. We want the input to be finite so our constructor will include a maximum number of time steps before the sine wave runs out. You will implement:public SineSource(Double a, Double f, Double d, int steps)
initializes the source using the given parameters;a
,f
, andd
correspond to parameters in the sine equation, whilesteps
is the total number of steps for which theSineSource
will have data.@Override public Double next()
Retrieves the next unit of data from the sine wave.@Override public boolean hasNext()
return false once theSineSource
has exceeded all of its allotted steps.
Once you’ve created this class and you think it works, you can try the following as a simple test to see what happens:
new SineSource(3.0, Math.PI/20, 0.0, 100).display();
DataFilter: (10p)public class DataFilter extends DataSource
This class takes another DataSource as input, and sends it directly through to thenext()
method. This will not be useful in and of itself, but we will derive classes later which modify this functionality in order to be able to do something interesting with the data. Like with the other sources, you have the following to implement:public DataFilter(DataSource src)
initializes so that the output of src is being used to send data to the output of this filter.@Override public Double next()
initializes so that the output of src is being used to send data from input to output.@Override public boolean hasNext()
this should depend on whether the input filter object still has data in it or not.
ScaleFilter: (10p)
public class ScaleFilter extends DataFilter
This filter doesn’t just pass the input to the output: it also multiplies it by a scaling constant before doing so. So if it has a scaling constant ofc=5.0
and it recieves an input of0.2
, then the output it produces withnext()
will be1.0
. This filter will implement the following:public ScaleFilter(DataSource src, Double c)
initializes the filter with the given data source and scaling constantc
.@Override public Double next()
.
SineScaleFilter: (10p)
public class SineScaleFilter extends DataFilter
This filter is similar to theScaleFilter
, except that instead of multiplying by a constant at every step, it multiplies by a sine wave (seeSineSource
) at every step. This filter will implement the following:public SineScaleFilter(DataSource src, Double a, Double f, Double d)
initializes the filter with the given data source and sine wave parametersa
for amplitude,f
for frequency, andd
for offset.@Override public Double next()
.
Implementation note: although you must derive this class from
DataFilter
, you are not required to derive directly fromDataFilter
. You can either leave the declaration as-is, or use a variant (for example, deriveSineScaleFilter
fromScaleFilter
, or derive both of them from some intermediate class).BufferedFilter: (20p)public class BufferedFilter extends DataFilter
While you’re reading data through the filter, it’s possible to use a buffer (in this case an array ofDouble
values) to remember input which you’ve already seen. For example, if you have an array of 20Double
values, then you can remember the past 20 input values which have passed through your filter. If you want to remember which data you’ve seen 5 time units ago, all you need to do is look back 5 places in your array.There’s a catch, though: when you begin, you only have a fixed-size buffer, but your input can go on for a long time. The input may be so long, that you don’t even want to keep a buffer large enough to capture all of it. Maybe your input is 100,000 time units long, but you only care about remembering the past 20 time steps. A solution is to use a circular buffer. The buffer fills up, but when it gets to the end, it starts back at the beginning and starts overwriting what’s already there. Basically, the buffer has a moving head and a moving tail.So if our buffer is length 20, at the beginning, our head is at position 0, our tail is at position 1, and the data for the previous time step is at position 19, and five time steps ago is at position 15. We read in a bit of data, and it gets stored at position 0. Now, the head is at position 1, the tail is at position 2, the previous time step (the one you’ve just read in) is at position 0, and five time steps ago is at position 16. Etc…For this class you implement a circular buffer which will store input values as you read them from the source, after which you forward them out as-is through the filter. You will implement the following:public BufferedFilter(DataSource src, int bufSize)
initializes the filter with the given data source and a buffer of lengthbufSize
. Hint: it’s expected that your array will be all zeros at the start, but if you declare a list ofDouble
values, their initial value would benull
instead of zero.public Double getLast(int t)
retrieve the memory of the input fromt
time units ago. Ift
is zero, then it refers to the most recently read input. Assume thatt
is within the range of the buffer size, otherwise the result is undefined.public Double inputNext()
this retrieves the next input value from the inputDataSource
, stores it in the circular buffer (updating anything you need to update in the process), and returns the value you’ve just read in.@Override public Double next()
usesinputNext()
to send on the next input from the source as-is.
EchoFilter: (10p)
public class EchoFilter extends BufferedFilter
This filter uses the memory of previous inputs to produce an echo effect. At every step, it will output a value which is the sum of the current input and an input from somen
steps ago. To do this, the following needs to be implemented:public EchoFilter(DataSource src, int echo)
initializes the filter with the given data source and an echo delay ofecho
. To produce an echo which is delayed by a certain number of steps, Think about how big of a buffer we need: if we want a delay of 1 step, for example, then our memory would need to store both the current step and the previous step, so two steps. What about if we want an echo delay of 5 steps? We’d need the previous five steps plus the current step, so a 6 step memory. So if we wanted a delay of lengthecho
, how big of a buffer do we need to ask for?@Override public Double next()
produces an output which is the result of adding the current input to the input fromecho
steps ago
- Create the
Got stuck with another paper? We can help! Use our paper writing service to score better grades and meet your deadlines.
Get 15% discount for your first order
Order a Similar Paper Order a Different Paper
