【问题标题】:"Must be already floating point" when converting an audio file into wav file将音频文件转换为 wav 文件时“必须已经是浮点数”
【发布时间】:2016-04-29 09:31:17
【问题描述】:

这里我有一个代码,用于将音频文件转换为 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);
}

【问题讨论】:

  • 请重新格式化您的问题,以便阅读。
  • @Hendry 希望你能看懂

标签: c# asp.net-mvc-4 naudio


【解决方案1】:

总体而言,代码和概念存在一些问题。

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

其次,您不需要MemoryStreamRawSourceWaveStreamWaveFileReaderWaveStream,适用于任何“下一级”NAudio 波处理器。

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

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

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

  1. 使用MediaFoundationReader 读取输入文件(我喜欢这个)
  2. 使用MediaFoundationResampler 将任何输入格式转换为16 位PCM(同时保持通道数)。请注意,这意味着您的输入文件不必与 A-law 输出具有相同的格式,因此它几乎可以转换任何内容。
  3. 将新的 16 位 PCM 流提供给自定义的“ALaw-to-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)
        {
        }
    }
}

【讨论】:

  • 使用了你的代码...它可以在 localhost 但在 iis 服务器中运行我收到类似“无法加载 DLL 'mfplat.dll”的错误:找不到指定的模块。 (来自 HRESULT 的异常:0x8007007E)”。
  • @Bob C 使用了您的代码...它可以在 localhost 但在 iis 服务器中运行我收到类似“无法加载 DLL 'mfplat.dll”的错误:找不到指定的模块。 (HRESULT 异常:0x8007007E)"
  • @JerryJohn - 这可能是也可能不是 NAudio 的事情。没有名为“mfplat.dll”的 NAudio 程序集,但它可能MediaFoundation 类相关。尝试用“普通”NAudio 类(如WaveFileReader 等)替换那些,然后查看它是否加载。或者,只需在另一个程序集中为此代码编写存根(即不使用任何 NAudio)并查看是否也出现异常。
  • @JerryJohn - 看起来 Mark Heath 也在你的问题中回答了。
【解决方案2】:

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

使用服务器管理器中的添加角色和功能向导。跳到功能并选择媒体基础

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-31
    • 2017-06-29
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多