#include #include #include #include #include struct _xas_riff { int fd; size_t size; }; static int header_write(xas_riff *riff) { xas_riff_wave_header header = { .riff = { { .id = "RIFF", .size = sizeof(xas_riff_wave_chunk) + sizeof(xas_riff_chunk) + riff->size }, .type = "WAVE" }, .wave = { { .id = "fmt ", .size = 16 }, .type = XAS_RIFF_WAVE_DEFAULT_TYPE, .channels = 1, .sample_rate = 44100, .byte_rate = 176400 / 2, .sample_size = 2, .sample_size_bits = 16 }, { .id = "data", .size = riff->size } }; if (lseek(riff->fd, 0, SEEK_SET) < 0) { goto error_io; } if (write(riff->fd, &header, sizeof(header)) < 0) { goto error_io; } if (lseek(riff->fd, 0, SEEK_END) < 0) { goto error_io; } return 0; error_io: return -1; } static xas_riff *file_open(const char *path, size_t sample_size, size_t sample_rate, size_t channels, int flags) { xas_riff *riff; if ((riff = malloc(sizeof(*riff))) == NULL) { goto error_malloc_riff; } riff->fd = (flags & O_CREAT)? open(path, flags, 0644): open(path, flags); if (riff->fd < 0) { goto error_open; } riff->size = 0; if (flags & (O_CREAT | O_TRUNC)) { if (header_write(riff) < 0) { goto error_header_write; } } return riff; error_header_write: close(riff->fd); error_open: free(riff); error_malloc_riff: return NULL; } static int file_close(xas_riff *riff) { if (lseek(riff->fd, 0, SEEK_SET) < 0) { goto error_io; } if (header_write(riff) < 0) { goto error_header_write; } (void)close(riff->fd); return 0; error_header_write: error_io: return -1; } static int audio_drain(xas_riff *riff, void *samples, size_t count, xas_audio_stream *stream) { size_t wrlen = count * stream->sample_size * stream->channels; return write(riff->fd, samples, wrlen); } static ssize_t audio_fill(xas_riff *riff, void *samples, size_t count, xas_audio_stream *stream) { ssize_t len = count * stream->sample_size * stream->channels; return read(riff->fd, samples, len); } xas_audio_stream *xas_riff_file_open(const char *path, size_t sample_size, size_t sample_rate, size_t channels, int flags) { xas_audio_stream *stream; xas_riff *riff; if ((riff = file_open(path, channels, sample_size, sample_rate, flags)) == NULL) { goto error_file_open; } if (flags & (O_RDWR | O_WRONLY)) { if ((stream = xas_audio_stream_new_sink((xas_audio_drain)audio_drain, riff, sample_size, sample_rate, channels, 4096)) == NULL) { goto error_audio_stream_new_sink; } } else { if ((stream = xas_audio_stream_new_source((xas_audio_fill)audio_fill, riff, sample_size, sample_rate, channels, 4096)) == NULL) { goto error_audio_stream_new_sink; } } return stream; error_audio_stream_new_sink: file_close(riff); error_file_open: return NULL; }