123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- /*
- * SPDX-FileCopyrightText: 2019 Helmut Pozimski <helmut@pozimski.eu>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- */
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdint.h>
- #include "wavfile.h"
- /* Important constants that represent chunk IDs or other
- * parts of the wave file
- */
- #define RIFF 0x46464952
- #define WAVE 0x45564157
- #define FMT 0x20746d66
- #define DATA 0x61746164
- #define MAX_DATA_BYTES 4294967295
- /* struct definitions for the chunk types in a wave file */
- /* common header for all chunks */
- typedef struct {
- uint32_t chunk_id;
- uint32_t chunk_size;
- } chunk_header;
- /* riff chunk at the beginning of the file */
- typedef struct {
- chunk_header riff_header;
- uint32_t riff_format;
- } riff_chunk;
- /* format sub-chunk */
- typedef struct {
- chunk_header format_header;
- uint16_t audioformat;
- uint16_t num_channels;
- uint32_t sample_rate;
- uint32_t byte_rate;
- uint16_t block_align;
- uint16_t bits_per_sample;
- } format_chunk;
- #define io_error_check(x, y) { if (x == -1) { free(y); return NULL; } }
- /*
- * Function: wavfile_create
- * --------------------------
- * Creates a wave file and writes the basic chunks into it
- *
- * file_name: name and path of the file to create
- * channels: number of sound channels
- * sample_rate: sampling rate for the audio data
- * bits_per_sample: bit width of one sample
- *
- * returns: a structure representing a wave file
- */
- wavfile * wavfile_create(const char * file_name, uint16_t channels, uint32_t sample_rate, uint32_t bits_per_sample) {
- wavfile * file = malloc(sizeof(wavfile));
- if (file == NULL) {
- return NULL;
- }
- int fd = open(file_name, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- if (fd == -1 ) {
- return NULL;
- }
- file->fd = fd;
- file->data_bytes_written = 0;
- riff_chunk riff_chunk = {
- .riff_header = {
- .chunk_id = RIFF,
- .chunk_size = 0
- },
- .riff_format = WAVE
- };
- io_error_check(write(fd, &riff_chunk, sizeof(riff_chunk)), file);
- format_chunk format_chunk = {
- .format_header = {
- .chunk_id = FMT,
- .chunk_size = 16
- },
- .audioformat = 1,
- .num_channels = channels,
- .sample_rate = sample_rate,
- .byte_rate = sample_rate * channels * (bits_per_sample / 8),
- .block_align = channels * (bits_per_sample / 8),
- .bits_per_sample = bits_per_sample
- };
- io_error_check(write(fd, &format_chunk, sizeof(format_chunk)), file);
- chunk_header data_header = {
- .chunk_id = DATA,
- .chunk_size = 0
- };
- io_error_check(write(fd, &data_header, sizeof(chunk_header)), file);
- return file;
- }
- /*
- * Function: wavfile_append_data
- * --------------------------
- * Appends an arbitrary amount of data to the data
- * section of a wave file
- *
- * file: pointer to the file structure
- * data: pointer to the data to be written
- * num_bytes: number of bytes to be written
- *
- * returns: an integer representing the number of bytes written
- */
- int wavfile_append_data(wavfile * file, void * data, uint32_t num_bytes) {
- uint32_t written;
- if (num_bytes + file->data_bytes_written > MAX_DATA_BYTES) {
- return 0;
- }
- written = write(file->fd, data, num_bytes);
- file->data_bytes_written += written;
- return written;
- }
- /*
- * Function: wavfile_close
- * -----------------------
- * Closes the file descriptor of a wave file
- * and writes the size information in the relevant chunks
- *
- * file: pointer to the file structure
- *
- * returns: 0 on success and -1 on failure
- */
- int wavfile_close(wavfile * file) {
- int err = 0;
- lseek(file->fd, 4, SEEK_SET);
- uint32_t file_size = 36 + file->data_bytes_written;
- err = write(file->fd, &file_size, 4);
- if (err == -1) {
- return err;
- }
- lseek(file-> fd, 40, SEEK_SET);
- err = write(file->fd, &file->data_bytes_written, 4);
- if (err == -1) {
- return err;
- }
- err = close(file->fd);
- free(file);
- return err;
- }
|