// serial_to_wav.c #include #include #include #include #include #include #include #define SERIAL_PORT "/dev/ttyESP32_A" #define BAUD_RATE B1500000 #define RATE 16000 #define CHANNELS 2 #define BPS 16 #define BLOCK_SIZE 512 // PCM bytes per block (128 stereo frames) #define MAGIC 0xABCD // header marker static volatile sig_atomic_t stop_flag = 0; void on_sigint(int sig) { (void)sig; stop_flag = 1; } void write_wav_header(FILE *f, uint32_t data_bytes) { uint32_t byte_rate = RATE * CHANNELS * (BPS/8); uint16_t block_align = CHANNELS * (BPS/8); uint32_t riff_size = 36 + data_bytes; fseek(f, 0, SEEK_SET); fwrite("RIFF", 1, 4, f); fwrite(&riff_size, 4, 1, f); fwrite("WAVE", 1, 4, f); fwrite("fmt ", 1, 4, f); uint32_t fmt_size = 16; fwrite(&fmt_size, 4, 1, f); uint16_t audio_fmt = 1; fwrite(&audio_fmt, 2, 1, f); uint16_t ch = CHANNELS; fwrite(&ch, 2, 1, f); uint32_t sr = RATE; fwrite(&sr, 4, 1, f); fwrite(&byte_rate, 4, 1, f); fwrite(&block_align, 2, 1, f); uint16_t bits = BPS; fwrite(&bits, 2, 1, f); fwrite("data", 1, 4, f); fwrite(&data_bytes, 4, 1, f); } int open_serial(const char *path) { int fd = open(path, O_RDONLY | O_NOCTTY); if (fd < 0) { perror("open"); return -1; } struct termios tio; if (tcgetattr(fd, &tio) != 0) { perror("tcgetattr"); close(fd); return -1; } cfsetispeed(&tio, BAUD_RATE); cfsetospeed(&tio, BAUD_RATE); tio.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR | IXON | IXOFF | IXANY | PARMRK | INPCK | ISTRIP); tio.c_oflag &= ~(OPOST); tio.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); tio.c_cflag &= ~(CSIZE | PARENB | CSTOPB | CRTSCTS); tio.c_cflag |= (CS8 | CLOCAL | CREAD); tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; if (tcsetattr(fd, TCSANOW, &tio) != 0) { perror("tcsetattr"); close(fd); return -1; } return fd; } int main() { signal(SIGINT, on_sigint); int fd = open_serial(SERIAL_PORT); if (fd < 0) return 1; FILE *out = fopen("capture.wav", "wb+"); if (!out) { perror("fopen"); close(fd); return 1; } uint32_t data_bytes = 0; fseek(out, 44, SEEK_SET); while (!stop_flag) { // Read header bytes explicitly uint8_t hbuf[2]; ssize_t hn = read(fd, hbuf, 2); if (hn != 2) continue; uint16_t hdr = hbuf[0] | (hbuf[1] << 8); // little-endian decode if (hdr != MAGIC) { // Not aligned, skip one byte and retry continue; } // Accumulate one full PCM block uint8_t block[BLOCK_SIZE]; size_t got = 0; while (got < BLOCK_SIZE && !stop_flag) { ssize_t m = read(fd, block + got, BLOCK_SIZE - got); if (m > 0) got += (size_t)m; } if (got == BLOCK_SIZE) { fwrite(block, 1, BLOCK_SIZE, out); data_bytes += BLOCK_SIZE; } } write_wav_header(out, data_bytes); fflush(out); fclose(out); close(fd); fprintf(stderr, "Saved capture.wav with %u bytes of audio\n", data_bytes); return 0; }