C++根据录音绘制波形图
时间: 2023-07-11 22:20:41 浏览: 129
要根据录音绘制波形图,可以采用以下步骤:
1. 读取录音文件,获取录音数据。
2. 计算每个采样点的振幅值,将其转换为可视化的点。
3. 绘制坐标轴和刻度线。
4. 将数据点连接起来,形成波形图。
以下是一个简单的示例代码,可以帮助你实现这个功能:
```c++
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <SFML/Graphics.hpp>
using namespace std;
// 定义采样率和采样位数
const int SAMPLE_RATE = 44100;
const int SAMPLE_BITS = 16;
// 定义绘制参数
const int WIDTH = 800;
const int HEIGHT = 400;
const int PADDING = 50;
const sf::Color AXIS_COLOR = sf::Color::White;
const sf::Color WAVE_COLOR = sf::Color::Green;
// 读取录音文件,获取录音数据
vector<double> readWavFile(string filename) {
ifstream file(filename, ios::binary);
if (!file.is_open()) {
cout << "Failed to open file: " << filename << endl;
return vector<double>();
}
// 跳过文件头
file.seekg(44);
vector<double> data;
while (true) {
short s;
file.read((char*)&s, sizeof(s));
if (file.eof()) {
break;
}
// 将采样值转换为 [-1, 1] 的范围
double v = (double)s / (double)SHRT_MAX;
data.push_back(v);
}
file.close();
return data;
}
// 计算每个采样点的坐标
vector<sf::Vector2f> calculatePoints(const vector<double>& data) {
vector<sf::Vector2f> points;
int n = data.size();
double dx = (double)(WIDTH - 2 * PADDING) / (double)n;
for (int i = 0; i < n; i++) {
double x = PADDING + i * dx;
double y = (1 - data[i]) * (HEIGHT - 2 * PADDING) / 2 + PADDING;
points.push_back(sf::Vector2f(x, y));
}
return points;
}
// 绘制坐标轴和刻度线
void drawAxis(sf::RenderWindow& window) {
sf::RectangleShape xaxis(sf::Vector2f(WIDTH - 2 * PADDING, 2));
xaxis.setPosition(PADDING, HEIGHT - PADDING);
xaxis.setFillColor(AXIS_COLOR);
window.draw(xaxis);
sf::RectangleShape yaxis(sf::Vector2f(2, HEIGHT - 2 * PADDING));
yaxis.setPosition(PADDING, PADDING);
yaxis.setFillColor(AXIS_COLOR);
window.draw(yaxis);
for (int i = 1; i <= 10; i++) {
double x = PADDING + (double)i * (WIDTH - 2 * PADDING) / 10;
sf::RectangleShape tick(sf::Vector2f(2, 10));
tick.setPosition(x, HEIGHT - PADDING);
tick.setFillColor(AXIS_COLOR);
window.draw(tick);
sf::Text label(to_string(i), sf::Font::getDefaultFont(), 16);
label.setPosition(x - 10, HEIGHT - PADDING + 10);
label.setFillColor(AXIS_COLOR);
window.draw(label);
}
}
// 绘制波形图
void drawWave(sf::RenderWindow& window, const vector<sf::Vector2f>& points) {
sf::VertexArray lines(sf::PrimitiveType::LineStrip, points.size());
for (int i = 0; i < points.size(); i++) {
lines[i].position = points[i];
lines[i].color = WAVE_COLOR;
}
window.draw(lines);
}
int main() {
// 读取录音文件
vector<double> data = readWavFile("recording.wav");
if (data.empty()) {
return 1;
}
// 计算每个采样点的坐标
vector<sf::Vector2f> points = calculatePoints(data);
// 创建窗口
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "Waveform");
// 主循环
while (window.isOpen()) {
// 处理事件
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
}
// 绘制波形图
window.clear();
drawAxis(window);
drawWave(window, points);
window.display();
}
return 0;
}
```
注意,这段代码使用了 SFML 库来绘制图形,需要在编译时链接该库。另外,为了简化代码,没有对异常情况进行处理,实际应用中需要进行错误处理。