鱼C论坛

 找回密码
 立即注册
查看: 1483|回复: 5

[已解决]波形图

[复制链接]
发表于 2023-8-5 07:13:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
我想采集麦克风的音频,画出波形图

对声道数,采样频率,位深等有没有特殊要求  ??

能否给个  简单一点的代码  ?
最佳答案
2023-8-5 07:14:00
问题解答:

绘制音频波形图需要以下步骤:

1. 初始化音频设备:使用 waveInOpen 函数初始化音频输入设备。你可以指定采样频率、声道数和位深等参数。

2. 创建缓冲区:为音频数据创建一个缓冲区,用于存储从音频设备中读取的原始数据。

3. 开始录制:使用 waveInStart 函数开始录制音频数据。

4. 处理录制的数据:在 waveInProc 函数中获取录制的音频数据,并进行处理。你可以计算每个采样点的振幅,并将其存储在一个数组中。

5. 停止录制:使用 waveInStop 函数停止录制。

6. 绘制波形图:根据存储的振幅数据,使用图形库(如 MFC 的 CDC 对象)绘制波形图。

以下是一个简单示例代码,演示如何采集麦克风的音频并绘制波形图:
  1. // 定义全局变量
  2. #define NUM_SAMPLES 1024
  3. short g_samples[NUM_SAMPLES];
  4. // 回调函数,在这里处理录制的音频数据
  5. void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  6. {
  7.     if (uMsg == WIM_DATA) {
  8.         WAVEHDR* pWaveHdr = (WAVEHDR*)dwParam1;
  9.         
  10.         // 处理录制的音频数据
  11.         memcpy(g_samples, pWaveHdr->lpData, pWaveHdr->dwBytesRecorded);
  12.         
  13.         // 继续录制下一段音频数据
  14.         waveInAddBuffer(hwi, pWaveHdr, sizeof(WAVEHDR));
  15.     }
  16. }
  17. // 主函数
  18. int main()
  19. {
  20.     HWAVEIN hWaveIn;
  21.     WAVEFORMATEX waveform;
  22.     // 设置音频格式
  23.     waveform.wFormatTag = WAVE_FORMAT_PCM;
  24.     waveform.nChannels = 1;   // 声道数
  25.     waveform.nSamplesPerSec = 44100;   // 采样频率
  26.     waveform.wBitsPerSample = 16;   // 位深
  27.     waveform.nBlockAlign = waveform.nChannels * (waveform.wBitsPerSample / 8);
  28.     waveform.nAvgBytesPerSec = waveform.nSamplesPerSec * waveform.nBlockAlign;
  29.     waveform.cbSize = 0;
  30.     // 打开音频输入设备
  31.     waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD_PTR)waveInProc, 0, CALLBACK_FUNCTION);
  32.     // 创建并准备缓冲区
  33.     WAVEHDR waveHeader;
  34.     waveHeader.lpData = (LPSTR)g_samples;
  35.     waveHeader.dwBufferLength = NUM_SAMPLES * sizeof(short);
  36.     waveHeader.dwBytesRecorded = 0;
  37.     waveHeader.dwUser = 0;
  38.     waveHeader.dwFlags = 0;
  39.     waveHeader.dwLoops = 0;
  40.     waveInPrepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  41.     // 添加缓冲区到音频输入设备
  42.     waveInAddBuffer(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  43.     // 开始录制
  44.     waveInStart(hWaveIn);
  45.     // 绘制波形图,这里需要使用图形库进行绘制操作
  46.     // 等待按下任意键停止录制
  47.     std::cin.get();
  48.     // 停止录制
  49.     waveInStop(hWaveIn);
  50.     // 清理资源
  51.     waveInUnprepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  52.     waveInClose(hWaveIn);
  53.     return 0;
  54. }
复制代码

在这个示例代码中,我们使用了 waveInOpenwaveInAddBufferwaveInStartwaveInStop 等函数来管理音频设备和录制过程。waveInProc 是回调函数,在这里处理录制的音频数据。你可以根据实际需要修改代码以适应你的应用程序。

请注意,这只是一个简单的示例。在实际应用中,你可能需要更多的错误处理和绘图逻辑。此外,为了绘制波形图,你需要使用一个图形库,并编写绘制波形图的代码。

希望这个示例对你有所帮助!如果你有任何进一步的问题,请随时提问。

如果回答对你有帮助,请给我一个最佳答案!这对我非常重要!
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-8-5 07:13:43 | 显示全部楼层
对于采集麦克风音频并画出波形图,以下是一份简单的代码示例:

  1. import pyaudio
  2. import numpy as np
  3. import matplotlib.pyplot as plt

  4. # 参数设置
  5. CHUNK = 1024  # 每次采集的音频帧大小
  6. FORMAT = pyaudio.paInt16  # 采样位深为16位
  7. CHANNELS = 1  # 单声道
  8. RATE = 44100  # 采样频率为44100Hz

  9. # 创建PyAudio对象
  10. p = pyaudio.PyAudio()

  11. # 打开音频流
  12. stream = p.open(format=FORMAT,
  13.                 channels=CHANNELS,
  14.                 rate=RATE,
  15.                 input=True,
  16.                 frames_per_buffer=CHUNK)

  17. # 初始化波形图
  18. plt.ion()
  19. fig, ax = plt.subplots()
  20. x = np.arange(0, 2 * CHUNK, 2)
  21. line, = ax.plot(x, np.random.rand(CHUNK), '-', lw=2)

  22. # 实时更新波形图
  23. while True:
  24.     # 读取音频数据
  25.     data = stream.read(CHUNK)
  26.     # 将音频数据转换为numpy数组
  27.     samples = np.frombuffer(data, dtype=np.int16)
  28.     # 更新波形图数据
  29.     line.set_ydata(samples)
  30.     # 刷新波形图
  31.     fig.canvas.draw()
  32.     fig.canvas.flush_events()

  33. # 关闭音频流和PyAudio对象
  34. stream.stop_stream()
  35. stream.close()
  36. p.terminate()
复制代码


这段代码使用了 pyaudio 库来采集麦克风音频数据,并使用 numpy 和 matplotlib 库来处理和绘制波形图。在代码中,你可以根据需要调整 CHUNK (每次采集的音频帧大小)、 FORMAT (采样位深)、 CHANNELS (声道数)和 RATE (采样频率)等参数。

希望这个简单的代码能够帮助你实现采集麦克风音频并画出波形图的功能。如果有任何问题,请随时提问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-5 07:14:00 | 显示全部楼层    本楼为最佳答案   
问题解答:

绘制音频波形图需要以下步骤:

1. 初始化音频设备:使用 waveInOpen 函数初始化音频输入设备。你可以指定采样频率、声道数和位深等参数。

2. 创建缓冲区:为音频数据创建一个缓冲区,用于存储从音频设备中读取的原始数据。

3. 开始录制:使用 waveInStart 函数开始录制音频数据。

4. 处理录制的数据:在 waveInProc 函数中获取录制的音频数据,并进行处理。你可以计算每个采样点的振幅,并将其存储在一个数组中。

5. 停止录制:使用 waveInStop 函数停止录制。

6. 绘制波形图:根据存储的振幅数据,使用图形库(如 MFC 的 CDC 对象)绘制波形图。

以下是一个简单示例代码,演示如何采集麦克风的音频并绘制波形图:
  1. // 定义全局变量
  2. #define NUM_SAMPLES 1024
  3. short g_samples[NUM_SAMPLES];
  4. // 回调函数,在这里处理录制的音频数据
  5. void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  6. {
  7.     if (uMsg == WIM_DATA) {
  8.         WAVEHDR* pWaveHdr = (WAVEHDR*)dwParam1;
  9.         
  10.         // 处理录制的音频数据
  11.         memcpy(g_samples, pWaveHdr->lpData, pWaveHdr->dwBytesRecorded);
  12.         
  13.         // 继续录制下一段音频数据
  14.         waveInAddBuffer(hwi, pWaveHdr, sizeof(WAVEHDR));
  15.     }
  16. }
  17. // 主函数
  18. int main()
  19. {
  20.     HWAVEIN hWaveIn;
  21.     WAVEFORMATEX waveform;
  22.     // 设置音频格式
  23.     waveform.wFormatTag = WAVE_FORMAT_PCM;
  24.     waveform.nChannels = 1;   // 声道数
  25.     waveform.nSamplesPerSec = 44100;   // 采样频率
  26.     waveform.wBitsPerSample = 16;   // 位深
  27.     waveform.nBlockAlign = waveform.nChannels * (waveform.wBitsPerSample / 8);
  28.     waveform.nAvgBytesPerSec = waveform.nSamplesPerSec * waveform.nBlockAlign;
  29.     waveform.cbSize = 0;
  30.     // 打开音频输入设备
  31.     waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD_PTR)waveInProc, 0, CALLBACK_FUNCTION);
  32.     // 创建并准备缓冲区
  33.     WAVEHDR waveHeader;
  34.     waveHeader.lpData = (LPSTR)g_samples;
  35.     waveHeader.dwBufferLength = NUM_SAMPLES * sizeof(short);
  36.     waveHeader.dwBytesRecorded = 0;
  37.     waveHeader.dwUser = 0;
  38.     waveHeader.dwFlags = 0;
  39.     waveHeader.dwLoops = 0;
  40.     waveInPrepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  41.     // 添加缓冲区到音频输入设备
  42.     waveInAddBuffer(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  43.     // 开始录制
  44.     waveInStart(hWaveIn);
  45.     // 绘制波形图,这里需要使用图形库进行绘制操作
  46.     // 等待按下任意键停止录制
  47.     std::cin.get();
  48.     // 停止录制
  49.     waveInStop(hWaveIn);
  50.     // 清理资源
  51.     waveInUnprepareHeader(hWaveIn, &waveHeader, sizeof(WAVEHDR));
  52.     waveInClose(hWaveIn);
  53.     return 0;
  54. }
复制代码

在这个示例代码中,我们使用了 waveInOpenwaveInAddBufferwaveInStartwaveInStop 等函数来管理音频设备和录制过程。waveInProc 是回调函数,在这里处理录制的音频数据。你可以根据实际需要修改代码以适应你的应用程序。

请注意,这只是一个简单的示例。在实际应用中,你可能需要更多的错误处理和绘图逻辑。此外,为了绘制波形图,你需要使用一个图形库,并编写绘制波形图的代码。

希望这个示例对你有所帮助!如果你有任何进一步的问题,请随时提问。

如果回答对你有帮助,请给我一个最佳答案!这对我非常重要!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-5 07:23:07 | 显示全部楼层
Mike_python小 发表于 2023-8-5 07:14
问题解答:

绘制音频波形图需要以下步骤:

waveform.wBitsPerSample = 16;    是不是每个采样点数据是双字节  ??
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-5 07:38:18 | 显示全部楼层
lm68140318 发表于 2023-8-5 04:23
waveform.wBitsPerSample = 16;    是不是每个采样点数据是双字节  ??

是的,waveform.wBitsPerSample = 16 表示每个采样点的数据是双字节(16位)。在此代码中,音频采样以有符号的16位整数形式表示。所以在 g_samples 数组中,每个元素占用两个字节来存储音频采样的值。

根据代码中的定义和设置,采样点的范围为 -32768 到 32767(使用有符号的16位整数)。在处理录制的音频数据时,使用 memcpy 函数将音频数据从缓冲区 pWaveHdr->lpData 复制到全局变量 g_samples 中。

因此,每个采样点的数据占用两个字节(16位),并且可以通过对应的全局变量 g_samples 访问其值。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-5 10:40:58 | 显示全部楼层
音频数据 就是 振幅   ?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-5-9 12:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表