【发布时间】:2010-11-24 04:55:25
【问题描述】:
我想使用 C# 语言和 .NET Framework 创建一个完善的可视化系统。 这可能看起来像在 Winamp 应用程序中。 也许存在免费图书馆或一些描述如何做到这一点的有趣文章? 例子: alt text http://img44.imageshack.us/img44/9982/examplel.png
【问题讨论】:
标签: c# .net audio bitmap noise
我想使用 C# 语言和 .NET Framework 创建一个完善的可视化系统。 这可能看起来像在 Winamp 应用程序中。 也许存在免费图书馆或一些描述如何做到这一点的有趣文章? 例子: alt text http://img44.imageshack.us/img44/9982/examplel.png
【问题讨论】:
标签: c# .net audio bitmap noise
你可以试试这些链接
OpenVP(是一个用于开发音乐可视化的免费开源平台,用 C# 编写),请参阅OpenVP Screenshots。
Play and Visualize WAV Files using Managed Direct Sound
再见。
【讨论】:
这是一个使用 WASAPI API 计算在计算机上播放的任何声音的 FFT 的脚本。它使用 CSCore 及其WinformsVisualization 示例:
using CSCore;
using CSCore.SoundIn;
using CSCore.Codecs.WAV;
using WinformsVisualization.Visualization;
using CSCore.DSP;
using CSCore.Streams;
using System;
public class SoundCapture
{
public int numBars = 30;
public int minFreq = 5;
public int maxFreq = 4500;
public int barSpacing = 0;
public bool logScale = true;
public bool isAverage = false;
public float highScaleAverage = 2.0f;
public float highScaleNotAverage = 3.0f;
LineSpectrum lineSpectrum;
WasapiCapture capture;
WaveWriter writer;
FftSize fftSize;
float[] fftBuffer;
SingleBlockNotificationStream notificationSource;
BasicSpectrumProvider spectrumProvider;
IWaveSource finalSource;
public SoundCapture()
{
// This uses the wasapi api to get any sound data played by the computer
capture = new WasapiLoopbackCapture();
capture.Initialize();
// Get our capture as a source
IWaveSource source = new SoundInSource(capture);
// From https://github.com/filoe/cscore/blob/master/Samples/WinformsVisualization/Form1.cs
// This is the typical size, you can change this for higher detail as needed
fftSize = FftSize.Fft4096;
// Actual fft data
fftBuffer = new float[(int)fftSize];
// These are the actual classes that give you spectrum data
// The specific vars of lineSpectrum here aren't that important because they can be changed by the user
spectrumProvider = new BasicSpectrumProvider(capture.WaveFormat.Channels,
capture.WaveFormat.SampleRate, fftSize);
lineSpectrum = new LineSpectrum(fftSize)
{
SpectrumProvider = spectrumProvider,
UseAverage = true,
BarCount = numBars,
BarSpacing = 2,
IsXLogScale = false,
ScalingStrategy = ScalingStrategy.Linear
};
// Tells us when data is available to send to our spectrum
var notificationSource = new SingleBlockNotificationStream(source.ToSampleSource());
notificationSource.SingleBlockRead += NotificationSource_SingleBlockRead;
// We use this to request data so it actualy flows through (figuring this out took forever...)
finalSource = notificationSource.ToWaveSource();
capture.DataAvailable += Capture_DataAvailable;
capture.Start();
}
private void Capture_DataAvailable(object sender, DataAvailableEventArgs e)
{
finalSource.Read(e.Data, e.Offset, e.ByteCount);
}
private void NotificationSource_SingleBlockRead(object sender, SingleBlockReadEventArgs e)
{
spectrumProvider.Add(e.Left, e.Right);
}
~SoundCapture()
{
capture.Stop();
capture.Dispose();
}
public float[] barData = new float[20];
public float[] GetFFtData()
{
lock (barData)
{
lineSpectrum.BarCount = numBars;
if (numBars != barData.Length)
{
barData = new float[numBars];
}
}
if (spectrumProvider.IsNewDataAvailable)
{
lineSpectrum.MinimumFrequency = minFreq;
lineSpectrum.MaximumFrequency = maxFreq;
lineSpectrum.IsXLogScale = logScale;
lineSpectrum.BarSpacing = barSpacing;
lineSpectrum.SpectrumProvider.GetFftData(fftBuffer, this);
return lineSpectrum.GetSpectrumPoints(100.0f, fftBuffer);
}
else
{
return null;
}
}
public void ComputeData()
{
float[] resData = GetFFtData();
int numBars = barData.Length;
if (resData == null)
{
return;
}
lock (barData)
{
for (int i = 0; i < numBars && i < resData.Length; i++)
{
// Make the data between 0.0 and 1.0
barData[i] = resData[i] / 100.0f;
}
for (int i = 0; i < numBars && i < resData.Length; i++)
{
if (lineSpectrum.UseAverage)
{
// Scale the data because for some reason bass is always loud and treble is soft
barData[i] = barData[i] + highScaleAverage * (float)Math.Sqrt(i / (numBars + 0.0f)) * barData[i];
}
else
{
barData[i] = barData[i] + highScaleNotAverage * (float)Math.Sqrt(i / (numBars + 0.0f)) * barData[i];
}
}
}
}
}
然后,当从不同的脚本中检索 barData 时,建议先锁定它,因为这是在单独的线程上修改的。
我不确定我从哪里得到GetSpectrumPoints,因为它似乎不在Github Repo 中,但在这里。只需将其粘贴到该文件中,我的代码就可以工作了。
public float[] GetSpectrumPoints(float height, float[] fftBuffer)
{
SpectrumPointData[] dats = CalculateSpectrumPoints(height, fftBuffer);
float[] res = new float[dats.Length];
for (int i = 0; i < dats.Length; i++)
{
res[i] = (float)dats[i].Value;
}
return res;
}
【讨论】:
GetSpectrumPoints() is a function anymore,并且检查 git 存储库历史记录也没有显示它。您介意澄清/更新您的答案吗? (我正在尝试将 Windows 上的音频捕获/处理与驱动 LED 灯的跨平台控制台应用程序集成;它只需要 0.0 到 1.0 条频率数据值)