将音频文件转换为 wav 文件时"Must be already floating point"



这里我有一个代码,用于将音频文件覆盖为wav格式,以获得更好的质量并减小文件大小。这里我使用的是naudio文件压缩源代码,当我尝试转换该文件时遇到了一个异常。

必须已经是浮点

public string ConvertToWAV(string tempFilePath, string tempFileName, string audioType)
{
    //Try to transform the file, if it fails use the original file            
    FileInfo fileInfo = new FileInfo(tempFilePath + tempFileName);
    byte[] fileData = new byte[fileInfo.Length];
    fileData = File.ReadAllBytes(tempFilePath + tempFileName);
    ISampleProvider sampleProvider;
    try
    {
        if (audioType.ToLower().Contains("wav"))
        {
            try
            {
                using (MemoryStream wav = new MemoryStream(fileData))
                {
                    WaveStream stream = new WaveFileReader(wav);
                    WaveFormat target = new WaveFormat();
                    var s = new RawSourceWaveStream(new MemoryStream(), new WaveFormat(8000, 16, 1));
                    var c = new WaveFormatConversionStream(WaveFormat.CreateALawFormat(8000, 1), s);
                    sampleProvider = new WaveToSampleProvider(c);
                    WaveFileWriter.CreateWaveFile16(tempFilePath + tempFileName, sampleProvider);
                    wav.Close();
                }
            }
            catch (Exception ex)
            {
                //We couldn't convert the file, continue with the original file.                        
            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return Convert.ToBase64String(fileData);
}

代码和概念通常存在一些问题。

首先,您将忽略输入文件的WaveFormat。我猜你假设它是8K,16位,1通道,基于你创建var s的线路,但这并不能保证。

其次,您不需要MemoryStreamRawSourceWaveStreamWaveFileReaderWaveStream,适用于任何"下一阶段"的NAudio波处理器。

第三(这很可能是你的例外):NAudio Wave处理器和转换器不喜欢WaveFormat中的A-Law(或u-Law)。A-Law(和u-Law)在技术上不是PCM数据。因此,它们不是NAudio喜欢玩的"波浪"数据。

好的,说到这里,这里有一些建议。在NAudio.Codecs名称空间中有非常特殊的A-Law和u-Law编码器。奇怪的是,它们被命名为ALawEncoderMuLawEncoder。这些东西是不兼容流,所以我们想让它们兼容。

我在末尾添加了一个类,它就是这样做的:创建一个IWaveProvider,它实际上吐出一个流a-Law或u-Law。下面是使用新类的测试代码。测试代码执行以下操作:

  1. 使用MediaFoundationReader读取输入文件(我喜欢这个)
  2. 使用MediaFoundationResampler将输入格式转换为16位PCM(同时保持通道计数)。请注意,这意味着您的输入文件不必具有与A定律输出相同的格式,因此它几乎可以转换任何内容
  3. 将新的16位PCM流馈送到自定义的"ALaw到IWaveProvider"转换器类
  4. 将兼容IWaveProvider的A-Law输出写入波形文件

我在这里使用MediaFoundation类,因为它们似乎不像基于ACM的类那样对波形格式特别。

    static void ConversionTest( string _outfilename, string _infilename )
    {
        try
        {
            using( var reader = new MediaFoundationReader(_infilename) )
            {
                // Create a wave format for 16-bit pcm at 8000 samples per second.
                int channels = reader.WaveFormat.Channels;
                int rate = 8000;
                int rawsize = 2;
                int blockalign = rawsize * channels; // this is the size of one sample.
                int bytespersecond = rate * blockalign;
                var midformat =
                    WaveFormat.CreateCustomFormat( WaveFormatEncoding.Pcm,
                                                   rate,
                                                   channels,
                                                   bytespersecond,
                                                   blockalign,
                                                   rawsize * 8 );
                // And a conversion stream to turn input into 16-bit PCM.
                var midstream = new MediaFoundationResampler(reader, midformat);
                //var midstream = new WaveFormatConversionStream(midformat, reader);
                // The output stream is our custom stream.
                var outstream = new PcmToALawConversionStream(midstream);

                WaveFileWriter.CreateWaveFile(_outfilename, outstream);
            }
        }
        catch( Exception _ex )
        {
        }
    }

这是一个将16位PCM转换为A-Law或u-Law的类。最后是A-Law或u-Law的专业:

    /// <summary>
    /// Encodes 16-bit PCM input into A- or u-Law, presenting the output
    /// as an IWaveProvider.
    /// </summary>
    public class PcmToG711ConversionStream : IWaveProvider
    {
        /// <summary>Gets the local a-law or u-law format.</summary>
        public WaveFormat WaveFormat { get { return waveFormat; } }
        /// <summary>Returns <paramref name="count"/> encoded bytes.</summary>
        /// <remarks>
        /// Note that <paramref name="count"/> is raw bytes.  It doesn't consider
        /// channel counts, etc.
        /// </remarks>
        /// <param name="buffer">The output buffer.</param>
        /// <param name="offset">The starting position in the output buffer.</param>
        /// <param name="count">The number of bytes to read.</param>
        /// <returns>The total number of bytes encoded into <paramref name="buffer"/>.</returns>
        public int Read(byte[] buffer, int offset, int count)
        {
            // We'll need a source buffer, twice the size of 'count'.
            int shortcount = count*2;
            byte [] rawsource = new byte [shortcount];
            int sourcecount = Provider.Read(rawsource, 0, shortcount);
            int bytecount = sourcecount / 2;
            for( int index = 0; index < bytecount; ++index )
            {
                short source = BitConverter.ToInt16(rawsource, index*2);
                buffer[offset+index] = Encode(source);
            }
            return bytecount;
        }

        /// <summary>
        /// Initializes and A-Law or u-Law "WaveStream".  The source stream
        /// must be 16-bit PCM!
        /// </summary>
        /// <param name="_encoding">ALaw or MuLaw only.</param>
        /// <param name="_sourcestream">The input PCM stream.</param>
        public PcmToG711ConversionStream( WaveFormatEncoding _encoding,
                                          IWaveProvider _provider )
        {
            Provider = _provider;
            WaveFormat sourceformat = Provider.WaveFormat;
            if( (sourceformat.Encoding != WaveFormatEncoding.Pcm) &&
                (sourceformat.BitsPerSample != 16) )
            {
                throw new NotSupportedException("Input must be 16-bit PCM.  Try using a conversion stream.");
            }
            if( _encoding == WaveFormatEncoding.ALaw )
            {
                Encode = this.EncodeALaw;
                waveFormat = WaveFormat.CreateALawFormat( _provider.WaveFormat.SampleRate,
                                                          _provider.WaveFormat.Channels) ;
            }
            else if( _encoding == WaveFormatEncoding.MuLaw )
            {
                Encode = this.EncodeMuLaw;
                waveFormat = WaveFormat.CreateMuLawFormat( _provider.WaveFormat.SampleRate,
                                                           _provider.WaveFormat.Channels) ;
            }
            else
            {
                throw new NotSupportedException("Encoding must be A-Law or u-Law");
            }
        }

        /// <summary>The a-law or u-law encoder delegate.</summary>
        EncodeHandler Encode;
        /// <summary>a-law or u-law wave format.</summary>
        WaveFormat waveFormat;
        /// <summary>The input stream.</summary>
        IWaveProvider Provider;
        /// <summary>A-Law or u-Law encoder delegate.</summary>
        /// <param name="_sample">The 16-bit PCM sample to encode.</param>
        /// <returns>The encoded value.</returns>
        delegate byte EncodeHandler( short _sample );
        byte EncodeALaw( short _sample )
        {
            return ALawEncoder.LinearToALawSample(_sample);
        }
        byte EncodeMuLaw( short _sample )
        {
            return MuLawEncoder.LinearToMuLawSample(_sample);
        }
    }

    public class PcmToALawConversionStream : PcmToG711ConversionStream
    {
        public PcmToALawConversionStream( IWaveProvider _provider )
          : base(WaveFormatEncoding.ALaw, _provider)
        {
        }
    }
    public class PcmToMuLawConversionStream : PcmToG711ConversionStream
    {
        public PcmToMuLawConversionStream( IWaveProvider _provider )
          : base(WaveFormatEncoding.MuLaw, _provider)
        {
        }
    }
}

我终于找到了这个问题的解决方案,即需要添加一种名为Media Foundation的附加功能,以便在Windows Server 2012中更好地工作。

使用服务器管理器中的"添加角色和功能"向导。跳到Features并选择Media Foundation

相关内容

最新更新