引入 maven 依赖:
<dependency><groupId>net.sourceforge.jtransforms</groupId><artifactId>jtransforms</artifactId><version>2.4.0</version></dependency>
FourierTransformTest.java:
import edu.emory.mathcs.jtransforms.fft.DoubleFFT_1D;import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;public class FourierTransformTest {public static void main(String[] args) throws UnsupportedAudioFileException, IOException {fastTest();// slowTest();}public static void fastTest() throws UnsupportedAudioFileException, IOException {double[] audio_src = AudioUtils.wavToDoubleArray( new File("C:\\E\\素材\\音频\\wav\\audio.wav") );// 将 audio_src 进行 时域转频域new DoubleFFT_1D(audio_src.length).realForward(audio_src);// 截取转换成频域以后得 audio_src 的前半部分 作为 audio_target// 这里拷贝频域模式下的 audio_src 的前半部分,因为是频域模式,所以前半部分和后半部分其实都包含 "完整" 的时域信息( 只是失真严重 ),如果是时域模式下直接砍一半,肯定会丢失一半的时域信息( 但是未丢失的时域信息的音质没有任何丢失 )// 所以频域下的double[]砍一半其实是音质砍一半( 即频率信息丢失一半 )// 这里 除以2实现了2x加速效果double[] audio_target = Arrays.copyOfRange(audio_src, 0, audio_src.length / 2);// 将 audio_target 进行频域转时域new DoubleFFT_1D( audio_target.length ).realInverse( audio_target, true );System.out.println("转换完毕");// 将audio_target 时域 double[] 转换成 wav 文件AudioUtils.doubleArrayToWAV( audio_target,new File( "C:\\E\\素材\\音频\\wav\\audio_target.wav" ) );System.out.println("生成完毕");}public static void slowTest() throws UnsupportedAudioFileException, IOException {double[] audio_src = AudioUtils.wavToDoubleArray( new File("C:\\E\\素材\\音频\\wav\\audio.wav") );// 将 audio_src 进行 时域转频域new DoubleFFT_1D(audio_src.length).realForward(audio_src);// 实现了 0.5X 变速效果double[] audio_zero = buildZeroDoubleValueArray( audio_src.length );// 将转换成频域以后的 audio_src 和一个等长度的 全是0的doublep[]合并( 可以把这个 audio_zero看做一个频域格式的 double[],只是各个频率下的振幅全是0)double[] audio_target = combineArray( audio_src,audio_zero );// 将 audio_target 频域转时域new DoubleFFT_1D( audio_target.length ).realInverse( audio_target, true );System.out.println("转换完毕");// 将时域格式下的 audio_target 转成 wav 文件AudioUtils.doubleArrayToWAV( audio_target,new File( "C:\\E\\素材\\音频\\wav\\audio_target.wav" ) );System.out.println("生成完毕");}private static double[] buildZeroDoubleValueArray(int length) {double[] doubleArray = new double[length];for (int i = 0; i < length; i++) {doubleArray[i]=0d;}return doubleArray;}private static double[] combineArray(double[]... arrays) {int arrayCount = arrays.length;int totalLength = 0;for( int i=0;i<arrayCount;i++ ){totalLength += arrays[ i ].length;}double[] array_combine = new double[ totalLength ];int index = 0;for( int arrayNum=0;arrayNum<arrayCount;arrayNum++ ){double[] array = arrays[arrayNum];for (double v:array){array_combine[index] = v;index++;}}return array_combine;}
}
用到的工具类 AudioUtils.java:
import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;public class AudioUtils {public static void main(String[] args) throws UnsupportedAudioFileException, IOException {File file = new File("C:\\E\\素材\\音频\\wav\\一生所爱.wav");double[] doubleArray = wavToDoubleArray(file);System.out.println( doubleArray.length );int partLength = doubleArray.length / 10;doubleArrayToWAV( Arrays.copyOfRange(doubleArray, 0, partLength),new File( "C:\\E\\素材\\音频\\wav\\一生所爱_part1.wav" ) );doubleArrayToWAV( Arrays.copyOfRange(doubleArray, partLength, partLength * 2),new File( "C:\\E\\素材\\音频\\wav\\一生所爱_part2.wav" ) );doubleArrayToWAV( Arrays.copyOfRange(doubleArray, partLength * 2, partLength * 3),new File( "C:\\E\\素材\\音频\\wav\\一生所爱_part3.wav" ) );doubleArrayToWAV( Arrays.copyOfRange(doubleArray, partLength * 3, partLength * 4),new File( "C:\\E\\素材\\音频\\wav\\一生所爱_part4.wav" ) );doubleArrayToWAV( Arrays.copyOfRange(doubleArray, partLength * 4, partLength * 5),new File( "C:\\E\\素材\\音频\\wav\\一生所爱_part5.wav" ) );doubleArrayToWAV( Arrays.copyOfRange(doubleArray, partLength * 5, partLength * 6),new File( "C:\\E\\素材\\音频\\wav\\一生所爱_part6.wav" ) );}public static double[] wavToDoubleArray(File mp3File) throws UnsupportedAudioFileException, IOException {AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(mp3File);AudioFormat audioFormat = audioInputStream.getFormat();int numChannels = audioFormat.getChannels();int sampleSizeInBytes = audioFormat.getSampleSizeInBits() / 8;int frameSize = numChannels * sampleSizeInBytes;int bufferSize = (int) (audioInputStream.getFrameLength() * frameSize);byte[] audioBytes = new byte[bufferSize];audioInputStream.read(audioBytes);double[] audioData = new double[audioBytes.length / 2];for (int i = 0, j = 0; i < audioBytes.length; i += 2, j++) {int sample = (audioBytes[i + 1] << 8) | (audioBytes[i] & 0xFF);audioData[j] = sample / 32768.0;}return audioData;}public static void doubleArrayToWAV(double[] audioData, File outputFile) throws IOException, UnsupportedAudioFileException {AudioFormat audioFormat = new AudioFormat(44100, 16, 2, true, false);byte[] audioBytes = new byte[audioData.length * 2];for (int i = 0, j = 0; i < audioData.length; i++, j += 2) {short sample = (short) (audioData[i] * 32767);audioBytes[j] = (byte) (sample & 0xFF);audioBytes[j + 1] = (byte) ((sample >> 8) & 0xFF);}AudioInputStream audioInputStream = new AudioInputStream(new ByteArrayInputStream(audioBytes), audioFormat, audioData.length);AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, outputFile);}
}