Создайте аудио спектр с AudioGraph UWP - PullRequest
0 голосов
/ 27 апреля 2019

Я хотел бы создать звуковой спектр (спектр с низкими, средними и высокими частотами. С классическим спектром, где ось X представляет частоты, а ось Y - объем, образованный вертикальными полосами)

Я получил среднюю громкость двух каналов, представленную процентной шкалой.

MainPage.xaml:

<Grid>
    <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,250">
        <Button x:Name="BtnFile" Width="150" Height="32" Content="Choose File" Click="BtnFile_Click" HorizontalAlignment="Center"/>
        <Button x:Name="BtnStartStop" Width="150" Height="32" Content="Start Graph" Margin="0,25,0,0" Click="BtnStartStop_Click" HorizontalAlignment="Center"/>
        <ProgressBar x:Name="ProgressVolume" Margin="0,25,0,0" Maximum="1" Width="350" Height="10"/>
    </StackPanel>
</Grid>

MainPage.xaml.cs:

private AudioGraph graph;
private AudioFileInputNode fileInput;
private AudioDeviceOutputNode deviceOutput;
private AudioFrameOutputNode frameOutputNode;

List<double> VolumeList = new List<double>();

DispatcherTimer VolumeTimer = new DispatcherTimer();

public MainPage()
{
    this.InitializeComponent();
    VolumeTimer.Interval = TimeSpan.FromMilliseconds(10);
    VolumeTimer.Tick += TimerVolume_Tick;
}

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    await CreateAudioGraph();
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    if (graph != null)
    {
        graph.Dispose();
    }
}

private async void BtnFile_Click(object sender, RoutedEventArgs e)
{
    if (fileInput != null)
    {
        fileInput.Dispose();
        if (BtnStartStop.Content.Equals("Stop Graph"))
        {
            TogglePlay();
        }
    }

    FileOpenPicker filePicker = new FileOpenPicker();
    filePicker.SuggestedStartLocation = PickerLocationId.MusicLibrary;
    filePicker.FileTypeFilter.Add(".mp3");
    filePicker.FileTypeFilter.Add(".wav");
    filePicker.FileTypeFilter.Add(".wma");
    filePicker.FileTypeFilter.Add(".m4a");
    filePicker.ViewMode = PickerViewMode.Thumbnail;
    StorageFile file = await filePicker.PickSingleFileAsync();

    if (file == null)
    {
        return;
    }

    CreateAudioFileInputNodeResult fileInputResult = await graph.CreateFileInputNodeAsync(file);
    if (AudioFileNodeCreationStatus.Success != fileInputResult.Status)
    {
        return;
    }

    fileInput = fileInputResult.FileInputNode;

    fileInput.AddOutgoingConnection(deviceOutput);
}

private void BtnStartStop_Click(object sender, RoutedEventArgs e)
{
     TogglePlay();
}

private void TogglePlay()
{
    if (BtnStartStop.Content.Equals("Start Graph"))
    {
        GraphStarting();
        BtnStartStop.Content = "Stop Graph";
        VolumeTimer.Start();
    }
    else
    {
        graph.Stop();
        VolumeTimer.Stop();
        BtnStartStop.Content = "Start Graph";
    }
}

private void GraphStarting()
{
    frameOutputNode = graph.CreateFrameOutputNode();
    fileInput.AddOutgoingConnection(frameOutputNode);
    graph.Start();
}

private void AudioGraph_QuantumProcessed(AudioGraph sender, object args)
{

    AudioFrame frame = frameOutputNode.GetFrame();
    ProcessFrameOutput(frame);
}

unsafe private void ProcessFrameOutput(AudioFrame frame)
{
    using (AudioBuffer buffer = frame.LockBuffer(AudioBufferAccessMode.Write))
    using (IMemoryBufferReference reference = buffer.CreateReference())
    {
        byte* dataInBytes;
        uint capacityInBytes;
        float* dataInFloat;

        // Get the buffer from the AudioFrame
        ((IMemoryBufferByteAccess)reference).GetBuffer(out dataInBytes, out capacityInBytes);

        dataInFloat = (float*)dataInBytes;

        double LeftValue = dataInFloat[0];
        double RightValue = dataInFloat[1];

        double MidValue = (Math.Abs(LeftValue) + Math.Abs(RightValue)) / 2;

        VolumeList.Add(MidValue);
    }
}

private void TimerVolume_Tick(object sender, object e)
{
    if (VolumeList.Count > 0)
    {
        ProgressVolume.Value = VolumeList[VolumeList.Count - 1];
    }
}

[ComImport]
[Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
unsafe interface IMemoryBufferByteAccess
{
    void GetBuffer(out byte* buffer, out uint capacity);
}

private async Task CreateAudioGraph()
{
    // Create an AudioGraph with default settings
        AudioGraphSettings settings = new AudioGraphSettings(AudioRenderCategory.Media);
    CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);

    if (result.Status != AudioGraphCreationStatus.Success)
    {
        return;
    }

    graph = result.Graph;

    // Create a device output node
    CreateAudioDeviceOutputNodeResult deviceOutputNodeResult = await graph.CreateDeviceOutputNodeAsync();

    if (deviceOutputNodeResult.Status != AudioDeviceNodeCreationStatus.Success)
    {
        return;
    }

    deviceOutput = deviceOutputNodeResult.DeviceOutputNode;

    graph.QuantumProcessed += AudioGraph_QuantumProcessed;
}

В этом посте я читал, что для этого можно использовать алгоритм FFT, и здесь я нашел проект с алгоритмом (FastFourierTransformation.cs), но я был не могу использовать его, начиная с тех данных, которые у меня есть, которые я назвал «MidValue».

Как можно создать спектр, начиная с "MidValue"?

(Правильно ли использовать таймер для установки значения громкости или это более правильно по-другому?)

Всегда спасибо!

...