Преобразование PCM 16 кГц в PCMU / 8 кГц с «потрескиванием» - можно ли это улучшить? - PullRequest
0 голосов
/ 02 апреля 2020

Я пытаюсь конвертировать в режиме реального времени в / из PCM (16 кГц, 16 бит, моно) в PCMA или PCMU (8 кГц, 8 бит, моно). Эта статья посвящена только кодированию (PCM-PCMA / U), но в конечном итоге мне нужно go в обе стороны.

Сначала я попробовал прямое кодирование (ALawEncoder.LinearToALawSample), но получилось с отличным качеством звук на половинной скорости. Итак, я сейчас смотрю на понижающую дискретизацию перед кодированием.

У меня есть код ниже - он обрабатывает понижающую выборку и кодирование. Результирующее аудио понятно, но очень хрипло. Нет заметной разницы между resampler.ResamplerQuality = 1 и resampler.ResamplerQuality = 60.

Без понижающей дискретизации звук идет медленно, но звучит не очень круто, поэтому я думаю, что это шаг повторной выборки, представляющий треск. Я заметил, что мой 640-байтовый вход для понижающей дискретизации становится 198 байтов - это кажется слишком низким (я бы наивно ожидал 50%), поэтому мне интересно, если это моя первая проблема. Входной файл PCM в Audacity, я до сих пор получаю очень чистый звук. Есть ли способ уменьшить частоту дискретизации с помощью NAudio и получить результаты, подобные Audacity?

Обратите внимание, что код в настоящее время читает из файла, но в конечном итоге я получу PCM 16 кГц в 640-байтовых блоках:

var inputBufferSize = 640;
var resampledBufferSize = 198;
var outputBufferSize = resampledBufferSize / 2;

// Downsample
var stream = new MemoryStream(_reader.ReadBytes(inputBufferSize));
var pcm16 = new NAudio.Wave.RawSourceWaveStream(stream, new WaveFormat(16000, 16, 1));
var resampled = new byte[resampledBufferSize];
using (var resampler = new MediaFoundationResampler(pcm16, new WaveFormat(8000, 16, 1)))
{
    resampler.ResamplerQuality = 60;
    var bytesRead = resampler.Read(resampled, 0, resampled.Length);
    Debug.WriteLine("BytesRead = " + bytesRead);
}

// Encode
byte[] encodedSample = new byte[outputBufferSize];
var outputIndex = 0;
for (int inputIndex = 0; inputIndex < resampledBufferSize; inputIndex += 2)
{
    if (_sendingFormat.FormatCodec == SDPMediaFormatsEnum.PCMA)
    {
        encodedSample[outputIndex] = ALawEncoder.LinearToALawSample(BitConverter.ToInt16(resampled, inputIndex));
    }
    else
    {
        encodedSample[outputIndex] = MuLawEncoder.LinearToMuLawSample(BitConverter.ToInt16(resampled, inputIndex));
    }
    outputIndex++;
}

SendAudioFrame((uint)encodedSample.Length, (int)_sendingFormat.FormatCodec, encodedSample);
...