#c# #ios #xamarin.ios #resampling #audiounit
#c# #iOS #xamarin.ios #передискретизация #audiounit
Вопрос:
Я использую аудиоустройство с типом VoiceProcessingIO для приема голоса без эха. В RenderCallback я получаю образцы звука, а затем устанавливаю все значения буфера равными нулю, чтобы не было воспроизведения. Теперь мне нужно изменить частоту дискретизации с 48000 до 16000 после получения звука, а затем пропустить полученный звук через фильтр нижних частот.
Я не могу понять, как настроить несколько аудиоустройств для подключения друг к другу и передачи данных.
Я знаю, что я должен использовать kAudioUnitSubType_AUConverter для конвертера и kAudioUnitSubType_LowPassFilter для фильтра.
Я уже отчаялся найти какую-либо помощь.
PS Я нашел это сообщение в блоге, есть аналогичная проблема, но автор так и не получил ответа на свой вопрос. Но я не понимаю, почему автор использует два конвертера. Я также обеспокоен тем, что он использует удаленный тип, и я не понимаю, почему он соединяет эти шины и в таком порядке.
public static class SoundSettings
{
public static readonly int SampleRate = 16000;
public static readonly int Channels = 1;
public static readonly int BytesPerSample = 2;
public static readonly int FramesPerPacket = 1;
}
private void SetupAudioSession()
{
AudioSession.Initialize();
AudioSession.Category = AudioSessionCategory.PlayAndRecord;
AudioSession.Mode = AudioSessionMode.GameChat;
AudioSession.PreferredHardwareIOBufferDuration = 0.08f;
}
private void PrepareAudioUnit()
{
_srcFormat = new AudioStreamBasicDescription
{
Format = AudioFormatType.LinearPCM,
FormatFlags = AudioFormatFlags.LinearPCMIsSignedInteger |
AudioFormatFlags.LinearPCMIsPacked,
SampleRate = AudioSession.CurrentHardwareSampleRate,
FramesPerPacket = SoundSettings.FramesPerPacket,
BytesPerFrame = SoundSettings.BytesPerSample * SoundSettings.Channels,
BytesPerPacket = SoundSettings.FramesPerPacket *
SoundSettings.BytesPerSample *
SoundSettings.Channels,
BitsPerChannel = SoundSettings.BytesPerSample * 8,
ChannelsPerFrame = SoundSettings.Channels,
Reserved = 0
};
var audioComponent = AudioComponent.FindComponent(AudioTypeOutput.VoiceProcessingIO);
_audioUnit = new AudioUnit.AudioUnit(audioComponent);
_audioUnit.SetEnableIO(true, AudioUnitScopeType.Input, 1);
_audioUnit.SetEnableIO(true, AudioUnitScopeType.Output, 0);
_audioUnit.SetFormat(_srcFormat, AudioUnitScopeType.Input, 0);
_audioUnit.SetFormat(_srcFormat, AudioUnitScopeType.Output, 1);
_audioUnit.SetRenderCallback(this.RenderCallback, AudioUnitScopeType.Input, 0);
}
private AudioUnitStatus RenderCallback(
AudioUnitRenderActionFlags actionFlags,
AudioTimeStamp timeStamp,
uint busNumber,
uint numberFrames,
AudioBuffers data)
{
var status = _audioUnit.Render(ref actionFlags, timeStamp, 1, numberFrames, data);
if (status != AudioUnitStatus.OK)
{
return status;
}
var msgArray = new byte[dataByteSize];
Marshal.Copy(data[0].Data, msgArray, 0, dataByteSize);
var msg = _msgFactory.CreateAudioMsg(msgArray, msgArray.Length, ( _lastIndex));
this.OnMsgReady(msg);
// Disable playback IO
var array = new byte[dataByteSize];
Marshal.Copy(array, 0, data[0].Data, dataByteSize);
return AudioUnitStatus.NoError;
}
Комментарии:
1. Похоже, у вас есть звуковая система, которая может обрабатывать голос или музыку. Во-первых, вам не нужно изменять частоту дискретизации, вы всегда можете добавить фильтрацию, чтобы получить более низкие частоты. Например, чтобы перейти от 48000 к 16000, вы можете просто взять каждую третью выборку. Данные, которые вы хотите получить от одного процесса и ввести во ввод второго процесса, и сделать это в режиме реального времени. Самый простой способ — создать FIFO и использовать таймеры.
2. Я реализовал «наивный» алгоритм для уменьшения частоты дискретизации. Я взял среднее значение из трех выборок. В принципе, я могу использовать любую интерполяцию, поскольку я не уверен, что входная частота дискретизации всегда будет равна 48000. Но, поскольку разница между 48000 и 16000 более чем в два раза больше, мне нужен фильтр, чтобы избежать искажения звука. В любом случае это то, что говорится в этой статье , в разделе «Передискретизация». В конце концов, использование возможностей системы предпочтительнее самодельных алгоритмов.
3. Вот список различных форматов: learn.microsoft.com/en-us/dotnet/api /…
Ответ №1:
Вот пример функции, которую вы можете использовать для подключения двух аудиоустройств (обратите внимание, что источник и назначение должны иметь одинаковый формат потока, прежде чем вы сможете их успешно подключить) :
OSStatus connectAudioUnits(AudioUnit source, AudioUnit destination, AudioUnitElement sourceOutput, AudioUnitElement destinationInput) {
AudioUnitConnection connection;
connection.sourceAudioUnit = source;
connection.sourceOutputNumber = sourceOutput;
connection.destInputNumber = destinationInput;
return AudioUnitSetProperty (
destination,
kAudioUnitProperty_MakeConnection,
kAudioUnitScope_Input,
destinationInput,
amp;connection,
sizeof(connection)
);
}