音频格式转换

7

我在将WAV文件的音频格式转换方面遇到了困难。

我正在从麦克风录制声音,声音以以下格式录制: PCM_SIGNED 44100.0 Hz,16位,单声道,每帧2个字节

我想将上述格式转换为, ULAW 8000.0 Hz,8位,单声道,每帧1个字节

我正在使用以下代码:

InputStream is = request.getInputStream(); 
            AudioInputStream ais = AudioSystem.getAudioInputStream(is);
            AudioFormat oldFormat = ais.getFormat();
            AudioFormat newFormat = new AudioFormat(AudioFormat.Encoding.ULAW, 8000, 8, 1, 1, 8000, false) ;
AudioInputStream lowResAIS = AudioSystem.getAudioInputStream(newFormat, ais); //Getting the below Exception on this line

我遇到了以下的错误:

java.lang.IllegalArgumentException: 不支持的转换:ULAW 8000.0 Hz、8 bit、单声道、1 字节/帧、从 PCM_SIGNED 44100.0 Hz、16 bit、单声道、2 字节/帧、小端格式

有没有人能帮我解决这个问题!!!

非常感谢!!!

2个回答

3
你有没有查看过文档
如果转换不支持,就会抛出IllegalArgumentException异常,请使用getTargetEncodings以编程方式检查给定格式的适用性,而无需依赖于异常,然后根据需要采取适当的措施(例如,回退到另一个格式,向用户提供无法实现该格式的反馈等),并非每个系统都安装了足够的编解码器来转换您所请求的特定格式。您假设自己的系统有足够的编解码器,但它会抛出异常,因为它无法转换为该格式。

嘿,Andrzej!感谢您的回复。我已经部分地阅读了文档。我以以下方式使用了getTargetEncodings()方法:code Encoding[] encArr = AudioSystem.getTargetEncodings(oldFormat); for(int i=0;i<encArr.length;i++){ System.out.println(i + "-->"+encArr[i]); } code 然后我得到了以下输出结果:0-->PCM_SIGNED 1-->PCM_UNSIGNED 2-->ALAW 3-->ULAW,请问您对此有什么看法?谢谢! - Vijay Suryawanshi
由于我得到了上面的输出,我的系统有编解码器可以转换为ULAW格式,我猜测。除此之外,还可能有其他异常的原因吗?你有什么想法? - Vijay Suryawanshi
1
它可能不支持转换的某些其他方面,例如采样率或位数。我对此并不完全了解,但是“下采样”的事实引起了我的注意(从44100到8000)。这通常很棘手,因为在4000和22050 Hz之间具有频率的数据信息将出现混叠,除非您将其滤出数据。因此,我猜这不是标准支持的转换。但是我敢打赌,考虑到您的输出,您可以将其转换为ULAW 44100 Hz。(我的最佳猜测。) - Phil Freihofner

2

这个班级可能会对你有所帮助。我在这里找到了它:

package uk.co.mmscomputing.sound;

import java.io.*;

public class CompressInputStream extends FilterInputStream{

  /*
    Convert mono PCM byte stream into A-Law u-Law byte stream

    static AudioFormat alawformat= new AudioFormat(AudioFormat.Encoding.ALAW,8000,8,1,1,8000,false);
    static AudioFormat ulawformat= new AudioFormat(AudioFormat.Encoding.ULAW,8000,8,1,1,8000,false);

    PCM 8000.0 Hz, 16 bit, mono, SIGNED, little-endian
    static AudioFormat pcmformat = new AudioFormat(8000,16,1,true,false);

  */

  static private Compressor alawcompressor=new ALawCompressor();
  static private Compressor ulawcompressor=new uLawCompressor();

  private Compressor compressor=null;

  public CompressInputStream(InputStream in, boolean useALaw)throws IOException{
    super(in);
    compressor=(useALaw)?alawcompressor:ulawcompressor; 
  }

  public int read()throws IOException{
    throw new IOException(getClass().getName()+".read() :\n\tDo not support simple read().");
  }

  public int read(byte[] b)throws IOException{
    return read(b,0,b.length);
  }

  public int read(byte[] b, int off, int len)throws IOException{
    int     i,sample;
    byte[]  inb;

    inb=new byte[len<<1];          // get 16bit PCM data
    len=in.read(inb);
    if(len==-1){return -1;};

    i=0;
    while(i<len){
      sample   = (inb[i++]&0x00FF);
      sample  |= (inb[i++]<<8);
      b[off++]=(byte)compressor.compress((short)sample);
    }
    return len>>1;
  }
}

abstract class Compressor{
  protected abstract int compress(short sample);    
}

/*
    Mathematical Tools in Signal Processing with C++ and Java Simulations
        by  Willi-Hans Steeb
            International School for Scientific Computing
*/

class ALawCompressor extends Compressor{

  static final int cClip = 32635;

  static final int[] ALawCompressTable ={
    1,1,2,2,3,3,3,3,
    4,4,4,4,4,4,4,4,
    5,5,5,5,5,5,5,5,
    5,5,5,5,5,5,5,5,
    6,6,6,6,6,6,6,6,
    6,6,6,6,6,6,6,6,
    6,6,6,6,6,6,6,6,
    6,6,6,6,6,6,6,6,
    7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7
  };

  protected int compress(short sample){
    int sign;
    int exponent;
    int mantissa;
    int compressedByte;

    sign = ((~sample) >> 8) & 0x80;
    if(sign==0){ sample *= -1;}
    if(sample > cClip){ sample = cClip; }
    if(sample >= 256){
      exponent = ALawCompressTable[(sample >> 8) & 0x007F];
      mantissa = (sample >> (exponent + 3) ) & 0x0F;
      compressedByte = 0x007F & ((exponent << 4) | mantissa);
    }else{
      compressedByte = 0x007F & (sample >> 4);
    }
    compressedByte ^= (sign ^ 0x55);
    return compressedByte;
  }
}

class uLawCompressor extends Compressor{

  static final int cClip = 32635;
  static final int cBias = 0x84;

  int[] uLawCompressTable ={
    0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
    4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
    5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
    5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
  };

  protected int compress(short sample){
    int sign;
    int exponent;
    int mantissa;
    int compressedByte;

    sign = (sample >> 8) & 0x80;
    if(sign!=0){ sample *= -1;}
    if(sample > cClip){ sample = cClip; }
    sample += cBias;

    exponent = uLawCompressTable[(sample >> 7) & 0x00FF];
    mantissa = (sample >> (exponent + 3)) & 0x0F;
    compressedByte = ~(sign | (exponent << 4) | mantissa);
    return compressedByte&0x000000FF;
  }
}

那是什么作用?它能帮我解决以下错误吗?“PCM_SIGNED 44100.0 Hz,16位,单声道,2字节/帧,小端不支持格式的行”。 - trusktr
我没有使用过它,但它声称可以将“单声道PCM字节流转换为A-Law u-Law字节流”。这看起来就像你想要做的事情。似乎在Java中不支持直接进行此转换,你必须自己进行压缩(就像这个类所做的那样)。 - 11101101b
1
结果证明我的错误是因为我不能使用已经被使用的数据线(所以错误是误导性的)。使用Beads声音库解决了我所有的问题(http://beadsproject.net)。 - trusktr
这可能没有回答楼主的问题,但对我来说与相关事项有关,很有用。 - Leif Gruenwoldt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接