我正在尝试使用Qt(c++)创建一个程序,该程序可以使用QAudioinput和QIODevice从麦克风记录音频。
现在,我想可视化我的信号
任何帮助,将不胜感激。谢谢
[Edit1] -从您的评论中复制(由Spektre撰写)
我两个通道都只有一个缓冲区
我使用Qt,通道的值在缓冲区上交错
这就是我如何分隔值
for ( int i = 0, j = 0; i < countSamples ; ++j)
{
YVectorRight[j]=Samples[i++];
YVectorLeft[j] =Samples[i++];
}
我绘制YvectorRight和YvectorLeft后的
。我看不到如何仅触发一个通道
这几年他在上课时为学生做过。我希望您知道示波器的工作原理,因此这里只是基础知识:
时基
fsmpl
是输入信号采样频率[Hz]
尝试使用尽可能大的
(44100,48000, ???)
,以便检测到的最大频率为
fsmpl/2
,这会为您提供时基轴的顶部。下限由缓冲区长度给出
绘制
创建函数,该函数将从指定的起始地址(内部缓冲区)中呈现采样缓冲区,方法如下:
Y刻度...振幅设置
Y偏移...垂直光束位置
X偏移...时移或水平位置
这可以通过修改起始地址或通过X偏移曲线来完成。
级别
创建将模拟级功能的函数。因此,从起始地址搜索缓冲区,如果幅度超过Level则停止。您可以有更多模式,但是这些是您应该实现的基础知识:
振幅:( < lvl ) -> ( > lvl )
振幅:( > lvl ) -> ( < lvl )
关卡还有许多其他可能性,例如毛刺,相对边缘,...
预览
您可以将所有这些放在一起,例如:有了start address
变量,因此可以将数据连续采样到某个缓冲区,并在计时器上使用level
调用start address
(并对其进行更新)。然后使用新的start address
调用draw并将timebase period
添加到start address
(当然根据您的示例)
多 channel
我使用行 IN,所以我有立体声输入(A,B =左,右),因此我可以添加一些其他内容,例如:
级别来源(A,B
,无)
渲染模式(时基,Chebyshev(如果关闭则为李沙育曲线))
Chebyshev = x
轴为A
,y
轴为B
,这将创建著名的Chebyshev图像,这些图像非常适合于相关的正弦信号。通常形成圆,椭圆,扭曲的循环...
其他东西
您可以为模拟电容或输入接地的通道添加滤波器,以及更多
GUI
您需要进行许多设置,我更喜欢模拟旋钮,而不是像真正的示波器那样使用按钮/滚动条/滑块
(半)模拟值:幅度,时基,电平,X偏移,Y偏移
离散值:电平模式(/,),电平源(A,B,-),每个通道(直接开,地面,关,容量开)
这是我的示波器的一些屏幕截图:
这是我的生成器的屏幕截图:
最后,在添加一些FFT之后,频谱分析仪
PS。
我从 DirectSound 开始,但是由于 buggy /非功能性缓冲区回调,它很烂
我现在对我的Apps中的所有声音使用 WinAPI WaveIn / Out 。经过几次怪癖之后,它是满足我的需求的最佳选择,并且具有最佳的延迟(Directsound的速度太慢超过10倍),但是对于示波器却没有任何好处(对于模拟器,我通常需要低延迟)
顺便说一句。我将这三个应用程序作为可链接的C++子窗口类(Borland)
,最后一次与我的ATMega168仿真器一起用于无传感器BLDC驱动程序调试
在这里您可以尝试我的Oscilloscope,generator and Spectrum analyser如果您对下载感到困惑,请阅读此帖子下方的评论 btw密码是:“oscill”
希望它对您有所帮助,只是在评论我时
[Edit1]触发
您一次触发所有通道,但通常仅从一个通道检查触发条件。现在实现很简单,例如,让
触发条件为
A(左)通道上升到级别以上,因此:
首先使连续播放而没有触发,您编写的是这样的:
for ( int i = 0, j = 0; i < countSamples ; ++j)
{
YVectorRight[j]=Samples[i++];
YVectorLeft[j] =Samples[i++];
}
// here draw or FFT,draw buffers YVectorRight,YVectorLeft
添加触发器
要添加触发条件,您只需找到满足条件的样本并从中开始绘图,就可以将其更改为如下所示
// static or global variables
static int i0=0; // actual start for drawing
static bool _copy_data=true; // flag that new samples need to be copied
static int level=35; // trigger level value datatype should be the same as your samples...
int i,j;
for (;;)
{
// copy new samples to buffer if needed
if (_copy_data)
for (_copy_data=false,i=0,j=0;i<countSamples;++j)
{
YVectorRight[j]=Samples[i++];
YVectorLeft[j] =Samples[i++];
}
// now search for new start
for (i=i0+1;i<countSamples>>1;i++)
if (YVectorLeft[i-1]<level) // lower then level before i
if (YVectorLeft[i]>=level) // higher then level after i
{
i0=i;
break;
}
if (i0>=(countSamples>>1)-view_samples) { i0=0; _copy_data=true; continue; }
break;
}
// here draw or FFT,draw buffers YVectorRight,YVectorLeft from i0 position
view_samples
是数据的查看/处理大小(对于一个或多个屏幕),应比(countSamples>>1)
少几倍
这个代码可以在边界区域上松开一个屏幕,以避免您需要实现循环缓冲区(环),但是对于初学者来说,这是可以的
只是通过某些if或switch语句对所有触发条件进行编码
我是一名优秀的程序员,十分优秀!