2014-02-05 301 views
1

我有一个声音文件,我正在练习相位声码。我已将文件的字节转换为double [],并通过快速傅里叶变换和快速傅立叶逆变换来处理该文件的波形。现在的问题是我需要将byte []转换回double。下面是一些有用的代码片段:Java如何将包含多个双精度的byte []转换为双精度[]

我如何在第一时间转换的数据:

/** 
* Converts bytes from a TargetDataLine into a double[] allowing the information to be read. 
* NOTE: One byte is lost in the conversion so don't expect the arrays to be the same length! 
* @param bufferData The buffer read in from the target Data Line 
* @return the double[] that the buffer has been converted into. 
*/ 
    private static double[] bytesToDoubleArray(byte[] bufferData){ 
    final int bytesRecorded = bufferData.length; 
    final int bytesPerSample = getAudioFormat().getSampleSizeInBits()/8; 
    final double amplification = 100.0; // choose a number as you like 
    double[] micBufferData = new double[bytesRecorded - bytesPerSample + 1]; 
    for (int index = 0, floatIndex = 0; index < bytesRecorded - bytesPerSample + 1; index += bytesPerSample, floatIndex++) { 
     double sample = 0; 
     for (int b = 0; b < bytesPerSample; b++) { 
      int v = bufferData[index + b]; 
      if (b < bytesPerSample - 1 || bytesPerSample == 1) { 
       v &= 0xFF; 
      } 
      sample += v << (b * 8); 
     } 
     double sample32 = amplification * (sample/32768.0); 
     micBufferData[floatIndex] = sample32; 

    } 
    return micBufferData; 
} 

和我在做什么的数据:

public static byte[] shift(byte[] data, int factor){ 
    double[] audioData = bytesToDoubleArray(data); 
    audioData = Arrays.copyOf(audioData, roundToPowerOf2(audioData.length)); 
    Complex[] transformed = FFT.fft(doubleToComplex(audioData)); 
    transformed = shiftArray(transformed, 3); 
    Complex[] reverted = FFT.ifft(transformed); 
    for(int i = 0; i<reverted.length; i++){ 
     audioData[i] = reverted[i].re(); 
    } 
    return null;//How do I convert audioData[] back into a byte[]???? 
} 

如何弥补任何想法这个问题?任何解决方案将不胜感激。另外任何已经实现相位声码处理的Java库都会非常棒。

+2

查找到'ByteBuffer'的序列,而不是序列。 –

+0

您可以通过阅读Double的规范来完成。 –

+0

但是你没有转换字节<=>双倍,你有效地转换字节<=>整数并将整数转换为双精度。如果使用相同的方案将双重结果转换回字节,您将失去一些重要意义。 –

回答

2

大约在这里。我确信我搞砸了。 scaleFactor大概是327.68,以扭转上面的缩放比例。上面的代码看起来很大。你是否想要f​​ullNormalize取决于你。

public byte[] doubleArrayToByteArray(double[] input, int bytesPerSample, double scaleFactor, boolean fullNormalize, boolean bigEndian) { 
    byte[] result = new byte[input.length * bytesPerSample]; 
    performNormalization(input, scaleFactor, fullNormalize); 
    for (int i = 0; i < input.length; i++) { 
     long sourceVal = (long)(input[i] * scaleFactor); 
     sourceVal = sourceVal >> 8 * (8 - bytesPerSample); 
     for (int j = 0; j < bytesPerSample; j++) { 
      int index = i * bytesPerSample; 
      if (bigEndian) { 
       index += (bytesPerSample - j); 
      } 
      else { 
       index += j; 
      } 
      result[index] = (byte) sourceVal; 
      sourceVal = sourceVal >> 8; 
     } 
    } 
    return result; 
} 

public void performNormalization(double[] input, double scaleFactor, boolean fullNormalize) { 
    double maxVal = 0.0; 
    for (int i = 0; i < input.length; i++) { 
     double val = Math.abs(input[i]) * scaleFactor; 
     if (val > maxVal) { 
      maxVal = val; 
     } 
    } 
    if (fullNormalize || maxVal > Long.MAX_VALUE) { 
     double normalizeFactor = (double)(Long.MAX_VALUE)/maxVal; 
     for (int i = 0; i < input.length; i++) { 
      input[i] *= normalizeFactor; 
     } 
    } 
} 

更新时间:意识到我需要考虑的标准化比例因子。而且通常不会指定不是1.0的scaleFactorfullNormalize = true

0

就像您从byte[]转换为double[]时那样,您现在需要转换回byte[]。只是创建一个新的byte[]阵列和手动从double[]阵列中的数据复制:

private static byte[] doublesToByteArray(double[] a) { 
    int len = a.length; 
    byte[] b = new byte[len]; 
    for (int i = 0; i < len; i++) 
     b[i] = (byte) a[i]; 
    return b; 
} 

这当然假定double[]阵列中的数据可以被存储在一个阵列byte[]无需进一步转换/缩放。否则,复制时需要注意。

+0

对于有3-4个字节的意义的情况,不会很好地工作,是吗? –

+0

这就是为什么我提到进一步的转换/缩放可能会或可能不需要取决于应用程序。我的任务不是质疑OP的动机 - 我只是回答实际问题。 – Grodriguez

1

这取决于您将double []转换为byte []的意思。回想一下,通常double是8个字节的长度,而byte是1个字节的长度。

如果你可以将你的double转换为无符号整数0-255(或者有符号-128-127),那么你只需要将每个double转换为字节并赋值给一个新的数组,否则你必须使用ByteBuffer :

int capacity = // calculate how much space you need for your byte array 
ByteBuffer byteBuf = ByteBuffer(capacity); 
for(double d : doubleArray) byteBuf.putDouble(d); 
byte[] byteArray = byteBuf.array(); 

有效上述方法并没有转换什么,但你只是解释字节流的字节双

+1

如果读取原始代码,则将N个整数(其中N是可变的)字节转换为一个双精度值,并且大概需要将双精度值转换回每个N整数字节。它不是简单地将双打映射到字节缓冲区中。 –