用声卡实现的存储示波器
文章目录
- 用声卡实现的存储示波器
-
- 背景知识
-
- 采样频率
- 量化精度
- 生产者/消费者模式
- 总体规划
-
- 设计目标
- 功能规划
- 界面规划
- 程序结构
- 从声卡采集数据
-
- 声音采集类的定义
- 消费者/生产者实例
- wxPython布局基础
-
- 最简单的窗口程序框架
- 界面布局方法
- 界面设计
-
- 示波器屏幕原型
- 框架原型
- 逻辑处理
-
- 声明主窗口的若干重要属性
- 在状态栏上显示采集到的数据时间长度
- 从数据队列中读出数据
背景知识
如果没有工科背景,就不要纠结于什么是示波器以及为什么要加上存储这个限定词了,我们还是关注重点吧:什么是音频信 们人耳能听到的声音的频率范围,大约在20Hz到20000Hz之间,低于下限的,叫次声波,超过上限的,叫超声波。麦克将声音变成了电流,这就是音频信 。音频信 有频率和幅度的变化,存储示波器可以把一段时间内的音频信 直观地显示在屏幕上。
采样频率
声音是连续的,麦克输出的音频信 也是连续的。计算机只能处理数字化信息,所以要对音频信 做数字化处理,这就是所谓的模(拟)数(字)转换或A/D转换,其本质是每隔一个固定间隔时间测量一次信 的大小,并用这个测量值近似代替这个时间间隔内的信 幅度。如果测量的频率超过信 最高频率的两倍,A/D转换就可以取得很好的效果。这个测量频率就是采样频率,业界的标准之一是44100Hz,是音频上限的两倍多一点。
量化精度
A/D转换过程中每次采样得到的数据都需要保存下来。采集到的信 大小,如果用一个字节表示,则信 的动态范围是从-128到127,用两个字节表示,则信 的动态范围是从-32768到32767。这就是所谓的量化精度。
生产者/消费者模式
让我们来想象一个包饺子的场景:有人负责擀皮儿,擀好的饺子皮儿一张张摞成一摞;有人负责包饺子,从成摞的饺子皮儿上揭起一张,放馅儿、捏紧,码放在平板上;有人负责煮饺子,一次取走一平板。擀皮儿、包饺子、煮饺子,是三道相互依赖又各自独立的工序,前道工序是生产者,后道工序是消费者,生产者和消费者之间使用缓冲区作为隔离,最大限度地解除二者之间的相互影响。
总体规划
设计目标
为了描述方便,我先把最终的效果贴在下面。
这段代码定义了一个音频采集(AudioCapture)类中,实例化时需要提供一个数据队列。从声卡读出的数据是str类型,需要使用numpy的fromstring()方法转成numpy的array类型。另外请注意,向队列中写数据时,采用的是非阻塞式的,如果队列已满,则会抛出异常,所以需要捕获该异常。
消费者/生产者实例
下面的代码,演示了一个典型的生产者/消费者模式:一个子线程负责采集数据并写入队列,一个子线程负责从队列中取出数据并显示。同时,也展示了如何创建及使用队列、如何创建及管理线程。
wxPython布局基础
最简单的窗口程序框架
万丈高楼平地起。几乎所有的窗口程序,都可以从下面这个基本框架开始。
源码:base.py
界面布局方法
在开始UI设计之前,有必要先来了解一下wxPython的控件布局理论。wx的所有控件几乎都有parent/id/pos/size/style等属性,其中pos是position的简写,这是一个二元组,表示控件左上角距离在其父级控件左上角的像素距离。我们可以通过设置每个控件的pos实现控件布局,这就是所谓的静态布局法。当程序窗口尺寸变化时,静态布局很难保持好的显示效果,所以更常用的布局方法是使用布局管理控件。
wx.BoxSizer是最常用的布局管理控件,可以将其视为控件容器。装入wx.BoxSizer中的所有控件,垂直或者水平排列。不同于大多数的控件有具体的形象,wx.BoxSizer是无形的、不可见的,实例化时也不需要parent/id/pos/size/style等属性,只需要指定是水平的还是垂直的。下面这段代码演示了如何使用wx.BoxSizer实现布局。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!