parent
b5056f142e
commit
9d3c08fa3f
1 changed files with 55 additions and 13 deletions
|
@ -12,6 +12,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
struct RecordContext {
|
||||||
|
struct SoundIoRingBuffer *ring_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
static enum SoundIoFormat prioritized_formats[] = {
|
static enum SoundIoFormat prioritized_formats[] = {
|
||||||
SoundIoFormatFloat32NE,
|
SoundIoFormatFloat32NE,
|
||||||
|
@ -43,13 +48,26 @@ static int prioritized_sample_rates[] = {
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static FILE *out_f = NULL;
|
static int min_int(int a, int b) {
|
||||||
|
return (a < b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
static void read_callback(struct SoundIoInStream *instream, int frame_count_min, int frame_count_max) {
|
static void read_callback(struct SoundIoInStream *instream, int frame_count_min, int frame_count_max) {
|
||||||
|
struct RecordContext *rc = instream->userdata;
|
||||||
struct SoundIoChannelArea *areas;
|
struct SoundIoChannelArea *areas;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
int frames_left = frame_count_max;
|
char *write_ptr = soundio_ring_buffer_write_ptr(rc->ring_buffer);
|
||||||
|
int free_bytes = soundio_ring_buffer_free_count(rc->ring_buffer);
|
||||||
|
int free_count = free_bytes / instream->bytes_per_frame;
|
||||||
|
|
||||||
|
if (free_count < frame_count_min) {
|
||||||
|
fprintf(stderr, "ring buffer overflow\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_frames = min_int(free_count, frame_count_max);
|
||||||
|
int frames_left = write_frames;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int frame_count = frames_left;
|
int frame_count = frames_left;
|
||||||
|
@ -63,13 +81,15 @@ static void read_callback(struct SoundIoInStream *instream, int frame_count_min,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!areas) {
|
if (!areas) {
|
||||||
fprintf(stderr, "hole\n");
|
// Due to an overflow there is a hole. Fill the ring buffer with
|
||||||
exit(1);
|
// silence for the size of the hole.
|
||||||
|
memset(write_ptr, 0, frame_count * instream->bytes_per_frame);
|
||||||
} else {
|
} else {
|
||||||
for (int frame = 0; frame < frame_count; frame += 1) {
|
for (int frame = 0; frame < frame_count; frame += 1) {
|
||||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||||
fwrite(areas[ch].ptr, 1, instream->bytes_per_sample, out_f);
|
memcpy(write_ptr, areas[ch].ptr, instream->bytes_per_sample);
|
||||||
areas[ch].ptr += areas[ch].step;
|
areas[ch].ptr += areas[ch].step;
|
||||||
|
write_ptr += instream->bytes_per_sample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,6 +103,9 @@ static void read_callback(struct SoundIoInStream *instream, int frame_count_min,
|
||||||
if (frames_left <= 0)
|
if (frames_left <= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int advance_bytes = write_frames * instream->bytes_per_frame;
|
||||||
|
soundio_ring_buffer_advance_write_ptr(rc->ring_buffer, advance_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void overflow_callback(struct SoundIoInStream *instream) {
|
static void overflow_callback(struct SoundIoInStream *instream) {
|
||||||
|
@ -145,6 +168,8 @@ int main(int argc, char **argv) {
|
||||||
if (!outfile)
|
if (!outfile)
|
||||||
return usage(exe);
|
return usage(exe);
|
||||||
|
|
||||||
|
struct RecordContext rc;
|
||||||
|
|
||||||
struct SoundIo *soundio = soundio_create();
|
struct SoundIo *soundio = soundio_create();
|
||||||
if (!soundio) {
|
if (!soundio) {
|
||||||
fprintf(stderr, "out of memory\n");
|
fprintf(stderr, "out of memory\n");
|
||||||
|
@ -183,7 +208,6 @@ int main(int argc, char **argv) {
|
||||||
fprintf(stderr, "Device: %s\n", selected_device->name);
|
fprintf(stderr, "Device: %s\n", selected_device->name);
|
||||||
|
|
||||||
soundio_device_sort_channel_layouts(selected_device);
|
soundio_device_sort_channel_layouts(selected_device);
|
||||||
struct SoundIoChannelLayout *layout = &selected_device->layouts[0];
|
|
||||||
|
|
||||||
int sample_rate = 0;
|
int sample_rate = 0;
|
||||||
int *sample_rate_ptr;
|
int *sample_rate_ptr;
|
||||||
|
@ -207,14 +231,11 @@ int main(int argc, char **argv) {
|
||||||
if (fmt == SoundIoFormatInvalid)
|
if (fmt == SoundIoFormatInvalid)
|
||||||
fmt = selected_device->formats[0];
|
fmt = selected_device->formats[0];
|
||||||
|
|
||||||
fprintf(stderr, "%s %dHz %s interleaved\n", layout->name, sample_rate, soundio_format_string(fmt));
|
FILE *out_f = fopen(outfile, "wb");
|
||||||
|
|
||||||
out_f = fopen(outfile, "wb");
|
|
||||||
if (!out_f) {
|
if (!out_f) {
|
||||||
fprintf(stderr, "unable to open %s: %s\n", outfile, strerror(errno));
|
fprintf(stderr, "unable to open %s: %s\n", outfile, strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SoundIoInStream *instream = soundio_instream_create(selected_device);
|
struct SoundIoInStream *instream = soundio_instream_create(selected_device);
|
||||||
if (!instream) {
|
if (!instream) {
|
||||||
fprintf(stderr, "out of memory\n");
|
fprintf(stderr, "out of memory\n");
|
||||||
|
@ -222,22 +243,43 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
instream->format = fmt;
|
instream->format = fmt;
|
||||||
instream->sample_rate = sample_rate;
|
instream->sample_rate = sample_rate;
|
||||||
instream->layout = *layout;
|
|
||||||
instream->read_callback = read_callback;
|
instream->read_callback = read_callback;
|
||||||
instream->overflow_callback = overflow_callback;
|
instream->overflow_callback = overflow_callback;
|
||||||
|
instream->userdata = &rc;
|
||||||
|
|
||||||
if ((err = soundio_instream_open(instream))) {
|
if ((err = soundio_instream_open(instream))) {
|
||||||
fprintf(stderr, "unable to open input stream: %s", soundio_strerror(err));
|
fprintf(stderr, "unable to open input stream: %s", soundio_strerror(err));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "%s %dHz %s interleaved\n",
|
||||||
|
instream->layout.name, sample_rate, soundio_format_string(fmt));
|
||||||
|
|
||||||
|
const int ring_buffer_duration_seconds = 30;
|
||||||
|
int capacity = ring_buffer_duration_seconds * instream->sample_rate * instream->bytes_per_frame;
|
||||||
|
rc.ring_buffer = soundio_ring_buffer_create(soundio, capacity);
|
||||||
|
if (!rc.ring_buffer) {
|
||||||
|
fprintf(stderr, "out of memory\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((err = soundio_instream_start(instream))) {
|
if ((err = soundio_instream_start(instream))) {
|
||||||
fprintf(stderr, "unable to start input device: %s", soundio_strerror(err));
|
fprintf(stderr, "unable to start input device: %s", soundio_strerror(err));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;) {
|
||||||
soundio_wait_events(soundio);
|
soundio_flush_events(soundio);
|
||||||
|
sleep(1);
|
||||||
|
int fill_bytes = soundio_ring_buffer_fill_count(rc.ring_buffer);
|
||||||
|
char *read_buf = soundio_ring_buffer_read_ptr(rc.ring_buffer);
|
||||||
|
size_t amt = fwrite(read_buf, 1, fill_bytes, out_f);
|
||||||
|
if ((int)amt != fill_bytes) {
|
||||||
|
fprintf(stderr, "write error: %s\n", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
soundio_ring_buffer_advance_read_ptr(rc.ring_buffer, fill_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
soundio_instream_destroy(instream);
|
soundio_instream_destroy(instream);
|
||||||
soundio_device_unref(selected_device);
|
soundio_device_unref(selected_device);
|
||||||
|
|
Loading…
Reference in a new issue