Browse Source

more reorganization of WPF demo code, also attempting to improve the FFT display

pull/1/head
markheath 14 years ago
parent
commit
ef2d33bd15
  1. 22
      NAudio/Dsp/FastFourierTransform.cs
  2. 0
      NAudioWpfDemo/AudioPlaybackDemo/AudioCapture.cs
  3. 0
      NAudioWpfDemo/AudioPlaybackDemo/AudioGraph.cs
  4. 0
      NAudioWpfDemo/AudioPlaybackDemo/AudioPlayback.cs
  5. 8
      NAudioWpfDemo/AudioPlaybackDemo/AudioPlaybackDemoPlugin.cs
  6. 12
      NAudioWpfDemo/AudioPlaybackDemo/AudioPlaybackDemoView.xaml
  7. 2
      NAudioWpfDemo/AudioPlaybackDemo/AudioPlaybackDemoView.xaml.cs
  8. 4
      NAudioWpfDemo/AudioPlaybackDemo/AudioPlaybackViewModel.cs
  9. 2
      NAudioWpfDemo/AudioPlaybackDemo/SampleAggregator.cs
  10. 0
      NAudioWpfDemo/AudioPlaybackDemo/WaveformVisual.cs
  11. 18
      NAudioWpfDemo/ControlPanel.xaml
  12. 27
      NAudioWpfDemo/ControlPanel.xaml.cs
  13. 28
      NAudioWpfDemo/NAudioWpfDemo.csproj
  14. 60
      NAudioWpfDemo/SpectrumAnalyser.xaml.cs

22
NAudio/Dsp/FastFourierTransform.cs

@ -2,17 +2,17 @@ using System;
namespace NAudio.Dsp
{
/// <summary>
/// Summary description for FastFourierTransform.
/// </summary>
public class FastFourierTransform
{
/// <summary>
/// This computes an in-place complex-to-complex FFT
/// x and y are the real and imaginary arrays of 2^m points.
/// </summary>
/// <summary>
/// Summary description for FastFourierTransform.
/// </summary>
public class FastFourierTransform
{
/// <summary>
/// This computes an in-place complex-to-complex FFT
/// x and y are the real and imaginary arrays of 2^m points.
/// </summary>
public static void FFT(bool forward, int m, Complex[] data)
{
{
int n, i, i1, j, k, i2, l, l1, l2;
float c1, c2, tx, ty, t1, t2, u1, u2, z;
@ -87,5 +87,5 @@ namespace NAudio.Dsp
}
}
}
}
}
}

0
NAudioWpfDemo/AudioCapture.cs → NAudioWpfDemo/AudioPlaybackDemo/AudioCapture.cs

0
NAudioWpfDemo/AudioGraph.cs → NAudioWpfDemo/AudioPlaybackDemo/AudioGraph.cs

0
NAudioWpfDemo/AudioPlayback.cs → NAudioWpfDemo/AudioPlaybackDemo/AudioPlayback.cs

8
NAudioWpfDemo/AudioPlaybackDemo.cs → NAudioWpfDemo/AudioPlaybackDemo/AudioPlaybackDemoPlugin.cs

@ -8,10 +8,10 @@ using System.ComponentModel.Composition;
namespace NAudioWpfDemo
{
[Export(typeof(IModule))]
class AudioPlaybackDemo : IModule
class AudioPlaybackDemoPlugin : IModule
{
AudioPlaybackDemoView view;
ControlPanelViewModel viewModel;
AudioPlaybackViewModel viewModel;
public string Name
{
@ -26,8 +26,8 @@ namespace NAudioWpfDemo
private void CreateView()
{
view = new AudioPlaybackDemoView();
this.viewModel = new ControlPanelViewModel(view.waveForm, view.analyzer);
view.controlPanel.DataContext = viewModel;
this.viewModel = new AudioPlaybackViewModel(view.waveForm, view.analyzer);
view.DataContext = viewModel;
}
public void Deactivate()

12
NAudioWpfDemo/AudioPlaybackDemoView.xaml → NAudioWpfDemo/AudioPlaybackDemo/AudioPlaybackDemoView.xaml

@ -14,6 +14,16 @@
</Grid.RowDefinitions>
<local:PolygonWaveFormControl x:Name="waveForm"/>
<local:SpectrumAnalyser x:Name="analyzer" Grid.Row="1"/>
<local:ControlPanel x:Name="controlPanel" Grid.Row="2" />
<StackPanel Orientation="Horizontal" Grid.Row="2">
<Button Command="{Binding CaptureCommand}" Margin="2" ToolTip="Record">
<Ellipse Fill="Red" Width="15" Height="15" Margin="3"/>
</Button>
<Button Command="{Binding StopCommand}" Margin="2" ToolTip="Stop">
<Rectangle Fill="DarkBlue" Width="15" Height="15" Margin="3" RadiusX="2" RadiusY="2"/>
</Button>
<Button Command="{Binding PlayFileCommand}" Margin="2" ToolTip="Play">
<Path Fill="DarkGreen" Margin="3" Width="15" Height="15" Data="M 0,0 L 1,1 L 0,2 Z" Stretch="Fill" StrokeLineJoin="Round"/>
</Button>
</StackPanel>
</Grid>
</UserControl>

2
NAudioWpfDemo/AudioPlaybackDemoView.xaml.cs → NAudioWpfDemo/AudioPlaybackDemo/AudioPlaybackDemoView.xaml.cs

@ -19,7 +19,7 @@ namespace NAudioWpfDemo
/// </summary>
public partial class AudioPlaybackDemoView : UserControl
{
ControlPanelViewModel viewModel;
AudioPlaybackViewModel viewModel;
public AudioPlaybackDemoView()
{

4
NAudioWpfDemo/ControlPanelViewModel.cs → NAudioWpfDemo/AudioPlaybackDemo/AudioPlaybackViewModel.cs

@ -10,14 +10,14 @@ using NAudio.Wave;
namespace NAudioWpfDemo
{
class ControlPanelViewModel : INotifyPropertyChanged, IDisposable
class AudioPlaybackViewModel : INotifyPropertyChanged, IDisposable
{
int captureSeconds;
AudioGraph audioGraph;
IWaveFormRenderer waveFormRenderer;
SpectrumAnalyser analyzer;
public ControlPanelViewModel(IWaveFormRenderer waveFormRenderer, SpectrumAnalyser analyzer)
public AudioPlaybackViewModel(IWaveFormRenderer waveFormRenderer, SpectrumAnalyser analyzer)
{
this.waveFormRenderer = waveFormRenderer;
this.analyzer = analyzer;

2
NAudioWpfDemo/SampleAggregator.cs → NAudioWpfDemo/AudioPlaybackDemo/SampleAggregator.cs

@ -30,7 +30,7 @@ namespace NAudioWpfDemo
{
throw new ArgumentException("FFT Length must be a power of two");
}
this.m = (int)Math.Log(fftLength, 2.0); // (int)(Math.Log(fftLength) / Math.Log(2.0) + 0.5);
this.m = (int)Math.Log(fftLength, 2.0);
this.fftLength = fftLength;
this.fftBuffer = new Complex[fftLength];
this.fftArgs = new FftEventArgs(fftBuffer);

0
NAudioWpfDemo/WaveformVisual.cs → NAudioWpfDemo/AudioPlaybackDemo/WaveformVisual.cs

18
NAudioWpfDemo/ControlPanel.xaml

@ -1,18 +0,0 @@
<UserControl x:Class="NAudioWpfDemo.ControlPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="Auto" Width="Auto">
<Grid Margin="5">
<StackPanel Orientation="Horizontal" >
<Button Command="{Binding CaptureCommand}" Margin="2" ToolTip="Record">
<Ellipse Fill="Red" Width="15" Height="15" Margin="3"/>
</Button>
<Button Command="{Binding StopCommand}" Margin="2" ToolTip="Stop">
<Rectangle Fill="DarkBlue" Width="15" Height="15" Margin="3" RadiusX="2" RadiusY="2"/>
</Button>
<Button Command="{Binding PlayFileCommand}" Margin="2" ToolTip="Play">
<Path Fill="DarkGreen" Margin="3" Width="15" Height="15" Data="M 0,0 L 1,1 L 0,2 Z" Stretch="Fill" StrokeLineJoin="Round"/>
</Button>
</StackPanel>
</Grid>
</UserControl>

27
NAudioWpfDemo/ControlPanel.xaml.cs

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace NAudioWpfDemo
{
/// <summary>
/// Interaction logic for ControlPanel.xaml
/// </summary>
public partial class ControlPanel : UserControl
{
public ControlPanel()
{
InitializeComponent();
}
}
}

28
NAudioWpfDemo/NAudioWpfDemo.csproj

@ -91,16 +91,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="AudioPlaybackDemoView.xaml">
<Page Include="AudioPlaybackDemo\AudioPlaybackDemoView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="ControlPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="PolygonWaveFormControl.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -135,8 +129,8 @@
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="AudioPlaybackDemo.cs" />
<Compile Include="AudioPlaybackDemoView.xaml.cs">
<Compile Include="AudioPlaybackDemo\AudioPlaybackDemoPlugin.cs" />
<Compile Include="AudioPlaybackDemo\AudioPlaybackDemoView.xaml.cs">
<DependentUpon>AudioPlaybackDemoView.xaml</DependentUpon>
</Compile>
<Compile Include="IModule.cs" />
@ -146,13 +140,10 @@
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="AudioCapture.cs" />
<Compile Include="AudioGraph.cs" />
<Compile Include="AudioPlayback.cs" />
<Compile Include="ControlPanel.xaml.cs">
<DependentUpon>ControlPanel.xaml</DependentUpon>
</Compile>
<Compile Include="ControlPanelViewModel.cs" />
<Compile Include="AudioPlaybackDemo\AudioCapture.cs" />
<Compile Include="AudioPlaybackDemo\AudioGraph.cs" />
<Compile Include="AudioPlaybackDemo\AudioPlayback.cs" />
<Compile Include="AudioPlaybackDemo\AudioPlaybackViewModel.cs" />
<Compile Include="MainWindowViewModel.cs" />
<Compile Include="PolygonWaveFormControl.xaml.cs">
<DependentUpon>PolygonWaveFormControl.xaml</DependentUpon>
@ -175,14 +166,14 @@
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="RelayCommand.cs" />
<Compile Include="SampleAggregator.cs" />
<Compile Include="AudioPlaybackDemo\SampleAggregator.cs" />
<Compile Include="SpectrumAnalyser.xaml.cs">
<DependentUpon>SpectrumAnalyser.xaml</DependentUpon>
</Compile>
<Compile Include="WaveFormControl.xaml.cs">
<DependentUpon>WaveFormControl.xaml</DependentUpon>
</Compile>
<Compile Include="WaveformVisual.cs" />
<Compile Include="AudioPlaybackDemo\WaveformVisual.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
@ -217,6 +208,7 @@
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

60
NAudioWpfDemo/SpectrumAnalyser.xaml.cs

@ -38,40 +38,66 @@ namespace NAudioWpfDemo
void SpectrumAnalyser_SizeChanged(object sender, SizeChangedEventArgs e)
{
CalculateXScale();
CalculateXScale();
}
private void CalculateXScale()
{
this.xScale = this.ActualWidth / bins;
this.xScale = this.ActualWidth / (bins / binsPerPoint);
}
private const int binsPerPoint = 2; // reduce the number of points we plot for a less jagged line?
private int updateCount;
public void Update(Complex[] fftResults)
{
// no need to repaint too many frames per second
if (updateCount++ % 2 == 0)
{
return;
}
if (fftResults.Length / 2 != bins)
{
this.bins = fftResults.Length / 2;
CalculateXScale();
}
this.xScale = this.ActualWidth / bins;
for (int n = 0; n < fftResults.Length / 2; n++)
for (int n = 0; n < fftResults.Length / 2; n+= binsPerPoint)
{
//double yScale = 1000
//double intensity = Math.Sqrt(fftResults[n].X * fftResults[n].X + fftResults[n].Y * fftResults[n].Y);
//double yPos = this.ActualHeight - intensity * yScale;
double yPos = GetYPosLog(fftResults[n]);
AddResult(n / binsPerPoint, yPos);
}
}
// can also try 5 * without the sqrt seems to give decent results
double intensityDB = 10 * Math.Log(Math.Sqrt(fftResults[n].X * fftResults[n].X + fftResults[n].Y * fftResults[n].Y));
double minDB = -96;
if (intensityDB < minDB) intensityDB = minDB;
double percent = intensityDB / minDB;
// we want 0dB to be at the top (i.e. yPos = 0)
double yPos = percent * this.ActualHeight;
private double GetYPosIntensityOnly(Complex c)
{
double yScale = 1000;
double intensity = Math.Sqrt(c.X * c.X + c.Y * c.Y);
double yPos = this.ActualHeight - intensity * yScale;
return yPos;
}
AddResult(n, yPos);
}
private double GetYPosLog(Complex c)
{
// in theory should be 20x to get the power, but doesn't seem to give me sensible values (may be because we throw half the FFT away - bin 0 might need to be halved)
double intensityDB = 10 * Math.Log(Math.Sqrt(c.X * c.X + c.Y * c.Y));
double minDB = -96;
if (intensityDB < minDB) intensityDB = minDB;
double percent = intensityDB / minDB;
// we want 0dB to be at the top (i.e. yPos = 0)
double yPos = percent * this.ActualHeight;
return yPos;
}
private double GetYPosAnotherTry(Complex c, int binNumber, int fftLength)
{
// this technique based on http://www.mathworks.com/support/tech-notes/1700/1702.html
double abs = Math.Sqrt(c.X * c.X + c.Y * c.Y); // do not scale by FFT length as NAudio already does this.
abs = abs * abs;
if (binNumber != 0) abs *= 2;
double yPos = abs * this.ActualHeight;
return yPos;
}
private void AddResult(int index, double power)

Loading…
Cancel
Save