wavfile.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. * SPDX-FileCopyrightText: 2019 Helmut Pozimski <helmut@pozimski.eu>
  3. *
  4. * SPDX-License-Identifier: GPL-2.0-only
  5. */
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <fcntl.h>
  11. #include <stdint.h>
  12. #include "wavfile.h"
  13. /* Important constants that represent chunk IDs or other
  14. * parts of the wave file
  15. */
  16. #define RIFF 0x46464952
  17. #define WAVE 0x45564157
  18. #define FMT 0x20746d66
  19. #define DATA 0x61746164
  20. #define MAX_DATA_BYTES 4294967295
  21. /* struct definitions for the chunk types in a wave file */
  22. /* common header for all chunks */
  23. typedef struct {
  24. uint32_t chunk_id;
  25. uint32_t chunk_size;
  26. } chunk_header;
  27. /* riff chunk at the beginning of the file */
  28. typedef struct {
  29. chunk_header riff_header;
  30. uint32_t riff_format;
  31. } riff_chunk;
  32. /* format sub-chunk */
  33. typedef struct {
  34. chunk_header format_header;
  35. uint16_t audioformat;
  36. uint16_t num_channels;
  37. uint32_t sample_rate;
  38. uint32_t byte_rate;
  39. uint16_t block_align;
  40. uint16_t bits_per_sample;
  41. } format_chunk;
  42. #define io_error_check(x, y) { if (x == -1) { free(y); return NULL; } }
  43. /*
  44. * Function: wavfile_create
  45. * --------------------------
  46. * Creates a wave file and writes the basic chunks into it
  47. *
  48. * file_name: name and path of the file to create
  49. * channels: number of sound channels
  50. * sample_rate: sampling rate for the audio data
  51. * bits_per_sample: bit width of one sample
  52. *
  53. * returns: a structure representing a wave file
  54. */
  55. wavfile * wavfile_create(const char * file_name, uint16_t channels, uint32_t sample_rate, uint32_t bits_per_sample) {
  56. wavfile * file = malloc(sizeof(wavfile));
  57. if (file == NULL) {
  58. return NULL;
  59. }
  60. int fd = open(file_name, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  61. if (fd == -1 ) {
  62. return NULL;
  63. }
  64. file->fd = fd;
  65. file->data_bytes_written = 0;
  66. riff_chunk riff_chunk = {
  67. .riff_header = {
  68. .chunk_id = RIFF,
  69. .chunk_size = 0
  70. },
  71. .riff_format = WAVE
  72. };
  73. io_error_check(write(fd, &riff_chunk, sizeof(riff_chunk)), file);
  74. format_chunk format_chunk = {
  75. .format_header = {
  76. .chunk_id = FMT,
  77. .chunk_size = 16
  78. },
  79. .audioformat = 1,
  80. .num_channels = channels,
  81. .sample_rate = sample_rate,
  82. .byte_rate = sample_rate * channels * (bits_per_sample / 8),
  83. .block_align = channels * (bits_per_sample / 8),
  84. .bits_per_sample = bits_per_sample
  85. };
  86. io_error_check(write(fd, &format_chunk, sizeof(format_chunk)), file);
  87. chunk_header data_header = {
  88. .chunk_id = DATA,
  89. .chunk_size = 0
  90. };
  91. io_error_check(write(fd, &data_header, sizeof(chunk_header)), file);
  92. return file;
  93. }
  94. /*
  95. * Function: wavfile_append_data
  96. * --------------------------
  97. * Appends an arbitrary amount of data to the data
  98. * section of a wave file
  99. *
  100. * file: pointer to the file structure
  101. * data: pointer to the data to be written
  102. * num_bytes: number of bytes to be written
  103. *
  104. * returns: an integer representing the number of bytes written
  105. */
  106. int wavfile_append_data(wavfile * file, void * data, uint32_t num_bytes) {
  107. uint32_t written;
  108. if (num_bytes + file->data_bytes_written > MAX_DATA_BYTES) {
  109. return 0;
  110. }
  111. written = write(file->fd, data, num_bytes);
  112. file->data_bytes_written += written;
  113. return written;
  114. }
  115. /*
  116. * Function: wavfile_close
  117. * -----------------------
  118. * Closes the file descriptor of a wave file
  119. * and writes the size information in the relevant chunks
  120. *
  121. * file: pointer to the file structure
  122. *
  123. * returns: 0 on success and -1 on failure
  124. */
  125. int wavfile_close(wavfile * file) {
  126. int err = 0;
  127. lseek(file->fd, 4, SEEK_SET);
  128. uint32_t file_size = 36 + file->data_bytes_written;
  129. err = write(file->fd, &file_size, 4);
  130. if (err == -1) {
  131. return err;
  132. }
  133. lseek(file-> fd, 40, SEEK_SET);
  134. err = write(file->fd, &file->data_bytes_written, 4);
  135. if (err == -1) {
  136. return err;
  137. }
  138. err = close(file->fd);
  139. free(file);
  140. return err;
  141. }