You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
6.2 KiB
178 lines
6.2 KiB
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <getopt.h>
|
|
#include <linux/spi/spidev.h>
|
|
#include <linux/types.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <unistd.h>
|
|
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <list>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
extern "C" {
|
|
#include "libiflytop_adc_capture.h"
|
|
}
|
|
|
|
using namespace std;
|
|
|
|
class WAVHeader {
|
|
public:
|
|
/**
|
|
* @brief WAV 文件头部信息的二进制格式
|
|
*
|
|
* WAV 文件头部信息包含了如下字段:
|
|
* - 固定为 "RIFF" 的 4 字节 chunk_id
|
|
* - 文件总大小 - 8 的 4 字节 chunk_size
|
|
* - 固定为 "WAVE" 的 4 字节 format
|
|
* - 固定为 "fmt " 的 4 字节 subchunk1_id
|
|
* - 固定为 16 的 4 字节 subchunk1_size
|
|
* - 编码格式,1 表示 PCM 编码的 2 字节 audio_format
|
|
* - 声道数,1 为单声道,2 为立体声的 2 字节 num_channels
|
|
* - 采样率,如 44100 的 4 字节 sample_rate
|
|
* - 数据传输速率,即采样率 * 声道数 * 位数 / 8 的 4 字节 byte_rate
|
|
* - 数据块对齐,即每个采样点占用的字节数,如 2 表示 16 位,即 2 字节的 2 字节 block_align
|
|
* - 位数,如 8、16、24、32 的 2 字节 bits_per_sample
|
|
* - 固定为 "data" 的 4 字节 subchunk2_id
|
|
* - 数据长度,即文件总大小 - 44 的 4 字节 subchunk2_size
|
|
*/
|
|
struct WAVHeaderBinary {
|
|
char chunk_id[4]; // 固定为 "RIFF"
|
|
uint32_t chunk_size; // 文件总大小 - 8
|
|
char format[4]; // 固定为 "WAVE"
|
|
char subchunk1_id[4]; // 固定为 "fmt "
|
|
uint32_t subchunk1_size; // 固定为 16
|
|
uint16_t audio_format; // 编码格式,1 表示 PCM 编码
|
|
uint16_t num_channels; // 声道数,1 为单声道,2 为立体声
|
|
uint32_t sample_rate; // 采样率,如 44100
|
|
uint32_t byte_rate; // 数据传输速率,即采样率 * 声道数 * 位数 / 8
|
|
uint16_t block_align; // 数据块对齐,即每个采样点占用的字节数,如 2 表示 16 位,即 2 字节
|
|
uint16_t bits_per_sample; // 位数,如 8、16、24、32
|
|
char subchunk2_id[4]; // 固定为 "data"
|
|
uint32_t subchunk2_size; // 数据长度,即文件总大小 - 44
|
|
};
|
|
WAVHeaderBinary header;
|
|
|
|
public:
|
|
WAVHeader() {}
|
|
void initialize(uint32_t sample_rate, uint16_t bits_per_sample, uint16_t num_channels, uint32_t wavbinsize) {
|
|
// 填充 RIFF 头
|
|
memcpy(header.chunk_id, "RIFF", 4);
|
|
header.chunk_size = wavbinsize + 44 - 8;
|
|
memcpy(header.format, "WAVE", 4);
|
|
|
|
// 填充 fmt 子块
|
|
memcpy(header.subchunk1_id, "fmt ", 4);
|
|
header.subchunk1_size = 16;
|
|
header.audio_format = 1; // PCM 编码
|
|
header.num_channels = num_channels;
|
|
header.sample_rate = sample_rate;
|
|
header.byte_rate = sample_rate * num_channels * bits_per_sample / 8;
|
|
header.block_align = num_channels * bits_per_sample / 8;
|
|
header.bits_per_sample = bits_per_sample;
|
|
|
|
// 填充 data 子块
|
|
memcpy(header.subchunk2_id, "data", 4);
|
|
header.subchunk2_size = wavbinsize;
|
|
}
|
|
void resize(uint32_t wavbinsize) {
|
|
header.chunk_size = wavbinsize + 44 - 8;
|
|
header.subchunk2_size = wavbinsize;
|
|
}
|
|
|
|
void dump() {
|
|
printf("chunk_id: %s\n", string(header.chunk_id, 4).c_str());
|
|
printf("chunk_size: %d\n", header.chunk_size);
|
|
printf("format: %s\n", string(header.format, 4).c_str());
|
|
printf("subchunk1_id: %s\n", string(header.subchunk1_id, 4).c_str());
|
|
printf("subchunk1_size: %d\n", header.subchunk1_size);
|
|
printf("audio_format: %d\n", header.audio_format);
|
|
printf("num_channels: %d\n", header.num_channels);
|
|
printf("sample_rate: %d\n", header.sample_rate);
|
|
printf("byte_rate: %d\n", header.byte_rate);
|
|
printf("block_align: %d\n", header.block_align);
|
|
printf("bits_per_sample: %d\n", header.bits_per_sample);
|
|
printf("subchunk2_id: %s\n", header.subchunk2_id);
|
|
printf("subchunk2_size: %d\n", header.subchunk2_size);
|
|
}
|
|
|
|
WAVHeader(uint32_t sample_rate, uint16_t bits_per_sample, uint16_t num_channels, uint32_t num_samples) {
|
|
initialize(sample_rate, bits_per_sample, num_channels, num_samples);
|
|
}
|
|
uint8_t* data() { return (uint8_t*)&header; }
|
|
size_t size() { return sizeof(header); }
|
|
};
|
|
|
|
void wavWriteVoice(string filename, uint32_t sample_rate, uint16_t bits_per_sample, uint16_t num_channels, const char* data, uint32_t size) {
|
|
fstream file;
|
|
WAVHeader wavHeader;
|
|
// logger->info("writeVoice filename:{} {} {} {} {}", filename, sample_rate, bits_per_sample, num_channels, size);
|
|
file.open(filename, fstream::in | fstream::out | fstream::binary);
|
|
if (!file.is_open()) {
|
|
file.open(filename, fstream::out | fstream::binary | fstream::trunc);
|
|
wavHeader.initialize(sample_rate, bits_per_sample, num_channels, 0);
|
|
file.seekp(0, ios::beg);
|
|
file.write((char*)wavHeader.data(), wavHeader.size());
|
|
file.close();
|
|
file.open(filename, fstream::in | fstream::out | fstream::binary);
|
|
}
|
|
|
|
// file.write(data, size);
|
|
#if 1
|
|
/**
|
|
* @brief 判断文件大小,文件大小大于等于44字节,说明文件已经存在,不需要写入头部
|
|
*/
|
|
file.seekp(0, ios::end);
|
|
file.write(data, size);
|
|
/**
|
|
* @brief 更新头部信息
|
|
*/
|
|
uint32_t filesize = file.tellp();
|
|
file.seekp(4, ios::beg);
|
|
uint32_t chunk_size = filesize - 8;
|
|
file.write((char*)&chunk_size, 4);
|
|
file.seekp(40, ios::beg);
|
|
uint32_t subchunk2_size = filesize - 44;
|
|
file.write((char*)&subchunk2_size, 4);
|
|
#endif
|
|
|
|
file.close();
|
|
}
|
|
|
|
void sound_capture_callback(int32_t* voicedata, uint32_t len) {
|
|
printf("sound_capture_callback:%d\n", len);
|
|
wavWriteVoice("record.wav", 48000, 32, 1, (char*)voicedata, len * sizeof(int32_t));
|
|
}
|
|
|
|
int main(int argc, char const* argv[]) {
|
|
system("rm -rf record.wav");
|
|
|
|
error_code_t erro_code = sound_capturer_init("/dev/spidev1.0", 59, sound_capture_callback);
|
|
if (erro_code != ksp_success) {
|
|
sound_capturer_dump_last_error();
|
|
return -1;
|
|
}
|
|
|
|
erro_code = sound_capturer_start();
|
|
if (erro_code != ksp_success) {
|
|
sound_capturer_dump_last_error();
|
|
return -1;
|
|
}
|
|
|
|
while (true) {
|
|
sleep(1);
|
|
}
|
|
|
|
return 0;
|
|
}
|