0
$\begingroup$

I make a simple sound equalizer that operates in frequency domain and lets user to adjust frequencies in sound by using 4 sliders. The first one responsible for 0 - 5kHz, the fourth one for 15-20kHz.

Steps are as follows:

  1. I read wav file and store it in float array
  2. I perform complex fft on that array (separately for left and right channel)
  3. I multiply real and imaginary parts of bins representing 0-5kHz frequencies (both positive and negative) by 1.1 3.981 to increase these low frequencies by 10% 12dB in the final sound.
  4. I perform ifft on array
  5. I alternate real parts of left and right channels (returned by ifft) to create the final audio

The problem is that after this process the sound is distorted. It sounds like the speakers were not plugged in correctly. I found that if I divide values returned by ifft by arbitrary constant then the final sound is right, but is much quieter. I make the division in time domain, on the results from ifft.

The problem doesn't occur if I multiply frequencies by a number less than 1. So if frequencies are attenuated no further division in time domain is needed.

I suppose there is a mistake in the whole process. But if all steps are fine, how should I deal with distorted sound? Is dividing in time domain a proper solution? What number should I use to divide the results then so the sound is not distorted?

EDIT

This is the code I use to perform presented steps. I use Apache Commons math implementation of FFT and SimpleAudioConversion class taken from there http://stackoverflow.com/a/26824664/2891664

Unfortunately, code highlighting doesn't work.

// read file and store playable content in byte array
File file = new File("/home/kamil/Downloads/Glory.wav");
AudioInputStream in = AudioSystem.getAudioInputStream(file);
AudioFormat fmt = in.getFormat();
byte[] bytes = new byte[in.available()];
int result = in.read(bytes);

// convert bytes to float array
float[] samples = new float[bytes.length * 8 / fmt.getSampleSizeInBits()];
int validSamples = SimpleAudioConversion.decode(bytes, samples, result, fmt);

// find nearest power of 2 to zero-pad array in order to use fft
int power = 0;
while (Math.pow(2, power) < samples.length / 2)
    power++;

// divide data into left and right channels
double[][] left = new double[2][(int) Math.pow(2, power)];
double[][] right = new double[2][(int) Math.pow(2, power)];

for (int i = 0; i < samples.length / 2; i++) {
    left[0][i] = samples[2 * i];
    right[0][i] = samples[2 * i + 1];
}

//fft
FastFourierTransformer.transformInPlace(left, DftNormalization.STANDARD, TransformType.FORWARD);
FastFourierTransformer.transformInPlace(right, DftNormalization.STANDARD, TransformType.FORWARD);

// here I amplify the 0-4kHz frequencies by 12dB
// 0-4kHz is 1/5 of whole spectrum, and since there are negative frequencies in the array
// I iterate over 1/10 and multiply frequencies on both sides of the array
for (int i = 1; i < left[0].length / 10; i++) {
    double factor = 3.981d; // ratio = 10^(12dB/20)
    //positive frequencies 0-4kHz
    left[0][i] *= factor;
    right[0][i] *= factor;
    left[1][i] *= factor;
    right[1][i] *= factor;

    // negative frequencies 0-4kHz
    left[0][left[0].length - i] *= factor;
    right[0][left[0].length - i] *= factor;
    left[1][left[0].length - i] *= factor;
    right[1][left[0].length - i] *= factor;
}

//ifft
FastFourierTransformer.transformInPlace(left, DftNormalization.STANDARD, TransformType.INVERSE);
FastFourierTransformer.transformInPlace(right, DftNormalization.STANDARD, TransformType.INVERSE);

// put left and right channel into array
float[] samples2 = new float[(left[0].length) * 2];
for (int i = 0; i < samples2.length / 2; i++) {
    samples2[2 * i] = (float) left[0][i];
    samples2[2 * i + 1] = (float) right[0][i];
}

// convert back to byte array which can be played
byte[] bytes2 = new byte[bytes.length];
int validBytes = SimpleAudioConversion.encode(samples2, bytes2, validSamples, fmt);

You may listen to the sound here https://vocaroo.com/i/s095uOJZiewf

$\endgroup$
  • $\begingroup$ I could not hear the audio. If the distortion is important, it looks like an implementation problem $\endgroup$ – Damien Dec 26 '18 at 17:52
  • $\begingroup$ The sound might be clipped. Check to see if you have values larger than 1 or smaller than -1 after the IFFT. $\endgroup$ – MBaz Dec 26 '18 at 17:59
  • $\begingroup$ It must not be your problem, but it does not seem a good idea to have such a tough transition between the frequency bands: a smooth weighting function should be better $\endgroup$ – Damien Dec 26 '18 at 18:18
  • $\begingroup$ I found similar problem here stackoverflow.com/questions/23298616/… People suggest using Hann window or/and some overlap algorithm. I apply whole audio to fft so I believe there is no need for any overlap-add or other similar thing in my code. I will try with Hann window. $\endgroup$ – mrJoe Dec 26 '18 at 18:34
  • $\begingroup$ I posted my code. Please tell me if you see something wrong. $\endgroup$ – mrJoe Dec 27 '18 at 11:57
0
$\begingroup$
  1. Chance are your output is clipping. Most commercial wave files are highly compressed (in terms of dynamics) and any type of processing is likely to cause clipping, unless you remove a lot of gain or apply a suitable limiter.
  2. Processing directly in the frequency domain is difficult and likely to result in time domain aliasing. That seems like a poor choice for an audio equalizer
  3. Your band selection is unusual. Most audio equalizer use log-spaced frequency bands to better match human auditory perception. You'll find, that there is almost no energy at all in the 15k-20k band.
$\endgroup$
  • $\begingroup$ My academic teacher suggested making a simple equalizer app working in frequency domain, not in real time. The course is about mobile applications, so this particular topic is rather something extraordinary and the whole point was to create something more interesting than typical CRUD app. But it seams that this task is more complicated than I supposed. In fact, I am not sure now if I should continue with that or just change my topic to simple create-read-update-delete mobile app. $\endgroup$ – mrJoe Dec 26 '18 at 18:56
  • $\begingroup$ Well, I posted my code. I would appreciate if you look at it. $\endgroup$ – mrJoe Dec 27 '18 at 11:57

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.