Skip to content

Commit 427cfe9

Browse files
ZheFeng7110H-Sofie
authored andcommitted
增加 通信软件技术(C++) 的课程实验资料
1 parent f4517d3 commit 427cfe9

File tree

11 files changed

+1638
-0
lines changed

11 files changed

+1638
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# 课程
2+
3+
通信软件技术(C++)
4+
5+
注意:本课程实际使用的教材是 《嵌入式Linux系统开发——基于ARM处理器通用平台》(冯新宇 著,清华大学出版社),课程内容是Linux开发,并没有讲C++。
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#include <alsa/asoundlib.h>
2+
#include <stdio.h>
3+
#include <stdlib.h>
4+
#include <time.h>
5+
#include <string.h>
6+
#include <sys/time.h>
7+
8+
// WAV文件头结构
9+
typedef struct {
10+
char chunk_id[4]; // "RIFF"
11+
int chunk_size; // 文件总长度 - 8
12+
char format[4]; // "WAVE"
13+
14+
char subchunk1_id[4]; // "fmt "
15+
int subchunk1_size; // 16 (PCM格式)
16+
short audio_format; // 1 (PCM)
17+
short num_channels; // 声道数
18+
int sample_rate; // 采样率
19+
int byte_rate; // 每秒字节数
20+
short block_align; // 每个样本的字节数
21+
short bits_per_sample; // 位深度
22+
23+
char subchunk2_id[4]; // "data"
24+
int subchunk2_size; // 音频数据长度
25+
} WavHeader;
26+
27+
// 获取当前时间(毫秒级精度)
28+
double get_current_time_ms() {
29+
struct timeval tv;
30+
gettimeofday(&tv, NULL);
31+
return (tv.tv_sec * 1000.0) + (tv.tv_usec / 1000.0);
32+
}
33+
34+
int main() {
35+
// ALSA设备参数
36+
const char *device = "default";
37+
snd_pcm_t *capture_handle;
38+
snd_pcm_hw_params_t *hw_params;
39+
int err;
40+
41+
// 音频参数
42+
unsigned int sample_rate = 44100; // 44.1 kHz
43+
int channels = 2; // 立体声
44+
snd_pcm_uframes_t frames = 1024; // 每周期帧数
45+
int bits_per_sample = 16; // 16位采样
46+
47+
// 计算录制时间(5秒)
48+
const int duration_sec = 5;
49+
const double duration_ms = duration_sec * 1000.0; // 转换为毫秒
50+
const size_t total_frames = sample_rate * duration_sec;
51+
const size_t buffer_size = frames * channels * (bits_per_sample / 8);
52+
53+
// 打开PCM设备
54+
if ((err = snd_pcm_open(&capture_handle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
55+
fprintf(stderr, "无法打开设备: %s\n", snd_strerror(err));
56+
return 1;
57+
}
58+
59+
// 分配硬件参数结构
60+
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
61+
fprintf(stderr, "无法分配参数: %s\n", snd_strerror(err));
62+
return 1;
63+
}
64+
65+
// 初始化参数
66+
if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) {
67+
fprintf(stderr, "无法初始化参数: %s\n", snd_strerror(err));
68+
return 1;
69+
}
70+
71+
// 设置参数:交错模式
72+
if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
73+
fprintf(stderr, "无法设置访问模式: %s\n", snd_strerror(err));
74+
return 1;
75+
}
76+
77+
// 设置采样格式
78+
snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
79+
if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, format)) < 0) {
80+
fprintf(stderr, "无法设置格式: %s\n", snd_strerror(err));
81+
return 1;
82+
}
83+
84+
// 设置声道数
85+
if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, channels)) < 0) {
86+
fprintf(stderr, "无法设置声道数: %s\n", snd_strerror(err));
87+
return 1;
88+
}
89+
90+
// 设置采样率
91+
unsigned int actual_rate = sample_rate;
92+
if ((err = snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &actual_rate, 0)) < 0) {
93+
fprintf(stderr, "无法设置采样率: %s\n", snd_strerror(err));
94+
return 1;
95+
}
96+
if (actual_rate != sample_rate) {
97+
fprintf(stderr, "警告:实际采样率 %u Hz (请求 %u Hz)\n", actual_rate, sample_rate);
98+
}
99+
100+
// 设置周期大小
101+
if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params, &frames, 0)) < 0) {
102+
fprintf(stderr, "无法设置周期大小: %s\n", snd_strerror(err));
103+
return 1;
104+
}
105+
106+
// 应用参数
107+
if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) {
108+
fprintf(stderr, "无法应用参数: %s\n", snd_strerror(err));
109+
return 1;
110+
}
111+
112+
// 释放参数结构
113+
snd_pcm_hw_params_free(hw_params);
114+
115+
// 准备设备
116+
if ((err = snd_pcm_prepare(capture_handle)) < 0) {
117+
fprintf(stderr, "无法准备设备: %s\n", snd_strerror(err));
118+
return 1;
119+
}
120+
121+
// 创建输出文件
122+
FILE *wav_file = fopen("recording.wav", "wb");
123+
if (!wav_file) {
124+
perror("无法创建WAV文件");
125+
return 1;
126+
}
127+
128+
// 预留WAV文件头位置
129+
WavHeader header;
130+
memset(&header, 0, sizeof(header));
131+
fwrite(&header, 1, sizeof(header), wav_file);
132+
133+
// 分配音频缓冲区
134+
char *buffer = malloc(buffer_size);
135+
if (!buffer) {
136+
perror("内存分配失败");
137+
return 1;
138+
}
139+
140+
// 录制音频(改进时间显示逻辑)
141+
size_t frames_recorded = 0;
142+
double start_time_ms = get_current_time_ms(); // 录制开始时间
143+
printf("开始录制...\n");
144+
145+
while (frames_recorded < total_frames) {
146+
// 计算已录制时间(毫秒)
147+
double current_time_ms = get_current_time_ms();
148+
double elapsed_ms = current_time_ms - start_time_ms;
149+
double remaining_ms = duration_ms - elapsed_ms;
150+
151+
double remain_time = remaining_ms / 1000.0;
152+
if (remain_time < 0.0) {
153+
remain_time = 0.0;
154+
}
155+
156+
// 显示倒计时(格式:剩余时间 秒.毫秒)
157+
printf("\r剩余时间: %5.3lf秒", remain_time);
158+
fflush(stdout);
159+
160+
// 从设备读取数据(保持不变)
161+
snd_pcm_uframes_t frames_to_read = frames;
162+
if (frames_recorded + frames_to_read > total_frames) {
163+
frames_to_read = total_frames - frames_recorded;
164+
}
165+
166+
if ((err = snd_pcm_readi(capture_handle, buffer, frames_to_read)) != frames_to_read) {
167+
fprintf(stderr, "读取错误: %s\n", snd_strerror(err));
168+
break;
169+
}
170+
171+
// 写入文件(保持不变)
172+
size_t bytes_to_write = frames_to_read * channels * (bits_per_sample / 8);
173+
fwrite(buffer, 1, bytes_to_write, wav_file);
174+
frames_recorded += frames_to_read;
175+
}
176+
177+
printf("\n录制完成\n");
178+
179+
// 填充WAV文件头
180+
size_t data_size = frames_recorded * channels * (bits_per_sample / 8);
181+
182+
memcpy(header.chunk_id, "RIFF", 4);
183+
header.chunk_size = 36 + data_size;
184+
memcpy(header.format, "WAVE", 4);
185+
186+
memcpy(header.subchunk1_id, "fmt ", 4);
187+
header.subchunk1_size = 16;
188+
header.audio_format = 1; // PCM
189+
header.num_channels = channels;
190+
header.sample_rate = sample_rate;
191+
header.byte_rate = sample_rate * channels * (bits_per_sample / 8);
192+
header.block_align = channels * (bits_per_sample / 8);
193+
header.bits_per_sample = bits_per_sample;
194+
195+
memcpy(header.subchunk2_id, "data", 4);
196+
header.subchunk2_size = data_size;
197+
198+
// 重写文件头
199+
fseek(wav_file, 0, SEEK_SET);
200+
fwrite(&header, 1, sizeof(header), wav_file);
201+
202+
// 清理资源
203+
fclose(wav_file);
204+
free(buffer);
205+
snd_pcm_close(capture_handle);
206+
207+
printf("文件已保存为 recording.wav\n");
208+
return 0;
209+
}

0 commit comments

Comments
 (0)