#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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; }