我读过这些问题:
Using the Apple FFT and Accelerate Framework
How do I set up a buffer when doing an FFT using the Accelerate framework?
iOS FFT Accerelate.framework draw spectrum during playback
它们都描述了如何使用加速框架设置 fft。在他们的帮助下,我能够设置 fft 并获得基本的频谱分析仪。现在,我正在显示我从 fft 获得的所有值。但是,我只想显示 10-15 个或可变数量的条形图来表示某些频率。就像 iTunes 或 WinAmp 电平表一样。 1. 我是否需要对一系列频率的幅度值进行平均?或者他们只是向您显示特定频率条的幅度? 2. 另外,我需要将震级值转换为分贝吗? 3. 如何将我的数据映射到某个范围。我是否针对我的声音位深度的最大分贝范围进行映射?获取 bin 的最大值将导致跳跃最大映射值。
我的渲染回调:
static OSStatus PlaybackCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
UInt32 maxSamples = kAudioBufferNumFrames;
UInt32 log2n = log2f(maxSamples); //bins
UInt32 n = 1 << log2n;
UInt32 stride = 1;
UInt32 nOver2 = n/2;
COMPLEX_SPLIT A;
float *originalReal, *obtainedReal, *frequencyArray, *window, *in_real;
in_real = (float *) malloc(maxSamples * sizeof(float));
A.realp = (float *) malloc(nOver2 * sizeof(float));
A.imagp = (float *) malloc(nOver2 * sizeof(float));
memset(A.imagp, 0, nOver2 * sizeof(float));
obtainedReal = (float *) malloc(n * sizeof(float));
originalReal = (float *) malloc(n * sizeof(float));
frequencyArray = (float *) malloc(n * sizeof(float));
//-- window
UInt32 windowSize = maxSamples;
window = (float *) malloc(windowSize * sizeof(float));
memset(window, 0, windowSize * sizeof(float));
// vDSP_hann_window(window, windowSize, vDSP_HANN_DENORM);
vDSP_blkman_window(window, windowSize, 0);
vDSP_vmul(ioBuffer, 1, window, 1, in_real, 1, maxSamples);
//-- window
vDSP_ctoz((COMPLEX*)in_real, 2, &A, 1, maxSamples/2);
vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_FORWARD);
vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_INVERSE);
float scale = (float) 1.0 / (2 * n);
vDSP_vsmul(A.realp, 1, &scale, A.realp, 1, nOver2);
vDSP_vsmul(A.imagp, 1, &scale, A.imagp, 1, nOver2);
vDSP_ztoc(&A, 1, (COMPLEX *) obtainedReal, 2, nOver2);
vDSP_zvmags(&A, 1, obtainedReal, 1, nOver2);
Float32 one = 1;
vDSP_vdbcon(obtainedReal, 1, &one, obtainedReal, 1, nOver2, 0);
for (int i = 0; i < nOver2; i++) {
frequencyArray[i] = obtainedReal[i];
}
// Extract the maximum value
double fftMax = 0.0;
vDSP_maxmgvD((double *)obtainedReal, 1, &fftMax, nOver2);
float max = sqrt(fftMax);
}
播放一些音乐,我得到从 -96db 到 0db 的值。 绘制一个点:
CGPointMake(i, kMaxSpectrumHeight * (1 - frequencyArray[i]/-96.));
给我一个相当圆润的曲线:
如果我不转换为 db,我可以通过将我的数组值乘以 10000 来绘图并获得漂亮的峰值。
我做错了什么吗?我如何才能显示可变数量的条形图?
最佳答案
- Do I need to average magnitude values from a range of frequencies? Or do they just show you a magnitude for the specific frequency bar?
是的,您肯定需要在您定义的范围内计算平均值。只显示一个 FFT bin 是疯狂的。
- Also, do I need to convert my magnitude values to db?
是的:dB 是对数刻度。并非巧合的是,人类的听觉也(大致)以对数尺度起作用。因此,如果您在绘制值之前采用值的 log2(),这些值对于人类来说看起来会更自然。
- How do I map my data to a certain range. Do I map against the max db range for my sounds bitdepth? Getting the max Value for a bin will lead to jumping max mapping values.
我发现最简单的事情(至少在概念上)是将您的值从任何格式转换为 0..1,即“标准化和缩放”浮点值。然后从那里你可以根据需要转换成你需要绘制的东西。例如
SInt16 rawValue = fft[0]; // let's say this comes back as 12990
float scaledValue = rawValue/32767.; // This is MAX_INT for 16-bit;
// dividing we get .396435438 which is much easier for most people
// to see conceptually as 39% of our max possible value
float displayValue = log2(scaledValue);
my_fft[0] = displayValue;
关于iOS FFT 绘制频谱,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15568607/
本人是音乐爱好者,从小就特别喜欢那个随着音乐跳动的方框效果,就是这个:arduino上一大把对,我忍你很久了,我就想用mpy做,全网没有,行我自己研究。果然兴趣是最好的老师,我之前有篇博客专门讲音频,有兴趣的可以回顾一下。提到可视化频谱,必然绕不开fft,大学学过这玩意,当时一心玩,老师讲的一个字都么听进去,网上教程简略扫了一下,大该就是把时域转频域的工具,我大mpy居然没有fft函数,奶奶的,先放着。音频信息如何收集?第一种傻瓜式的ADC,模拟转数字,原始粗暴,第二种,I2S库,我之前博客有讲过,数据是PCM编码。然后又去学PCM编码,一学豁然开朗,舒服,以代码为例:audio_in=I2S
我正在寻找一种简单的方法来绘制大约10个点和矩形,以便能够查看我的算法哪里出了问题。我查看了gnuplot,但似乎绘制矩形特别糟糕。 最佳答案 SVG(MDNTutorial)是一种非常简单的基于文本(XML)的格式,您可以使用Ruby轻松生成它,而无需任何SVG库,并可以在任何现代Web浏览器中查看。这是一个示例:通过字符串插值的SVG点points=(0..5).map{[rand(100)-50,rand(100)-50]}puts#{points.map{|x,y|""}.join("\n")}ENDSVG输出:http:/
我想画一个点,大约1秒后我想画下一个点。这是否可能:我已经试过了:functionsimulate(i){setTimeout(function(){drawPoint(vis,i,i);},1000);}for(vari=1;i不幸的是,这是行不通的。它只是立即绘制整条线。 最佳答案 这是行不通的,因为for循环将立即运行到结束,setTimeouts将被同时调度,所有函数将同时触发。取而代之的是,这样做:vari=1;(functionloop(){if(i++>200)return;setTimeout(function(){
我正在使用GoogleMapsAPIV3在Googlemap中绘制一些自由形式的多边形,而不是标准库附带的标准点击多边形。一切都很好。问题:多边形生成大量可编辑点。如何在需要时简化多边形并创建可编辑点?这里是我的代码:varlatlng=newgoogle.maps.LatLng(46.779231,6.659431);varoptions={center:latlng,zoom:19,mapTypeId:google.maps.MapTypeId.ROADMAP,draggable:false};varmap=newgoogle.maps.Map(document.getElemen
我正在尝试绘制一个分类的多轴排名柱形图。排名第一的应该是最高的列,最低的排名应该是最短的。基本上我希望条形的高度是倒数。非常接近:varplayer_name_array=["AaronRodgers","AndrewLuck","DrewBrees","RussellWilson","PeytonManning","RyanTannehill","TonyRomo","MattRyan","CamNewton","BenRoethlisberger","EliManning","PhilipRivers","ColinKaepernick","TeddyBridgewater","M
我编写了这个无辜的javascript代码,它允许用户创建两个标记并绘制它们之间的路线。它不起作用,相反,它给出了一个奇怪的错误:UncaughtTypeError:Cannotreadproperty'ya'ofundefined有人可以告诉我这里出了什么问题吗://calleduponaclickGEvent.addListener(map,"click",function(overlay,point){if(isCreateHeadPoint){//addtheheadmarkerheadMarker=newGMarker(point,{icon:redIcon,title:'H
我正在使用Fabric.js,我想在Canvas上绘制弧线。我能找到的最接近的形状是Circle形状。当然,这只能让我画一个圆,而不是像跨越45°或180°的弧。有没有办法用Fabric.js来完成这个?如果没有,有没有办法获取底层上下文,然后创建弧并允许fabric管理它?保留Fabric.js提供的选择和缩放功能很重要。 最佳答案 在最新版本的FabricJSforcircle中添加了startAngle和endAngle属性。https://github.com/kangax/fabric.js/pull/1675varcan
我有一个力导向图,每个节点之间都有链接。现在一些节点对有多个相互连接的链接。我找到了这个例子:Drawingmultipleedgesbetweentwonodeswithd3.我觉得这很管用。但是如果你有固定的节点并拖动,路径最终会相互重叠。我整理了这个例子的编辑版本:http://jsfiddle.net/thatOneGuy/7HZcR/502/单击按钮固定节点并四处移动它们以了解我的意思。计算弧度的代码://sortlinksbysource,thentargetlinks.sort(function(a,b){if(a.source>b.source){return1;}el
我目前有一个Recharts组件,我想将其导出为PNG文件。(this.currentChart=chart)}width={this.state.width}height={this.state.height}data={this.testData}margin={{top:5,right:30,left:20,bottom:5}}>;但我不确定图书馆是否直接支持这一点。我有一个想法,涉及使用Canvas和2D渲染上下文让我接近解决方案,如MDN中所述。但是,我不确定将HTML元素(或React组件)呈现为Canvas以实现此解决方案的通用方法。我可能做错了这一切,我将不胜感激!
我是d3.js的新手,不确定要使用哪个d3功能。我需要围绕原点(在一个圆圈中)同心放置一组元素。svg.selectAll('circle').each(function(){d3.select(this).attr('cx',r*Math.cos(theta)).attr('cy',r*Math.sin(theta));theta+=thetaInc;});所以与其像上面的代码那样做一些乏味的事情,d3的简短方法是什么? 最佳答案 执行此操作的d3方法是传入数据并根据数据的索引计算位置,即类似于vartheta=2*Math.PI