Есть пара проблем с кодом и концепции в целом.
Во-первых, вы игнорируете входной файл WaveFormat
. Я предполагаю, что вы предполагаете, что это 8K, 16-бит, 1 канал на основе линии, где вы создаете var s
, но это не гарантия.
Во-вторых, вам не нужен MemoryStream
или RawSourceWaveStream
. WaveFileReader
- это WaveStream
, и он подходит для любого волнового процессора NA следующей ступени.
Третий (и это, скорее всего, ваше исключение): Процессоры и конвертеры NAudio Wave не любят закон A-закона (или u-Law) в WaveFormat
. A-Law (и u-Law) технически не является данными PCM. Таким образом, они не являются «волновыми» данными, с которыми NAudio любит играть.
Хорошо, со всем этим сказанным, вот несколько советов. В пространстве имен NAudio.Codecs
есть очень специальные кодеры A-Law и u-Law. Как ни странно, их называют ALawEncoder
и MuLawEncoder
. Эти вещи не потоко-совместимые, поэтому мы хотим сделать их совместимыми.
Я добавил класс в конце здесь, который делает именно это: Создает IWaveProvider
, который фактически выплескивает закон A-закона или U-закона. Вот тестовый код, который использует новый класс. Тестовый код выполняет следующие действия:
- читает входной файл с помощью
MediaFoundationReader
(я как этого)
- Преобразует независимо от формата входного сигнала в 16-разрядный PCM (при сохранении числа каналов) с помощью
MediaFoundationResampler
. Обратите внимание, что это означает, что ваш входной файл не должен иметь тот же формат, что и выход A-law, поэтому он будет конвертировать практически все.
- Подает этот новый 16-разрядный поток PCM в пользовательский класс преобразования «ALaw-to-IWaveProvider».
- Записывает вывод
IWaveProvider
-A-Law в файл волны.
Здесь я использую классы MediaFoundation
, потому что они, похоже, не так характерны для волновых форматов, как для ACM-based.
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 или у-закона. В конце являются специализациями для A-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)
{
}
}
}
Пожалуйста, переформатируйте свой вопрос, чтобы его можно было легко прочитать. – Hendry
@Hendry надеюсь, что вы можете его прочитать –