ref: e2f1e6d0d5e0a949bd1e4210448b6c597f27a68b
parent: 9630fa8f612fcb679ac42cb490e89b9dcd7f1d83
parent: a2019c416f1683d78e5cbfb20d7b8e655eb3d92b
author: Paul Brossier <piem@piem.org>
date: Thu Dec 20 15:30:50 EST 2018
Merge branch 'feature/sink_vorbis' into feature/sink_flac
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,7 +18,7 @@
- python: 3.4
os: linux
compiler: gcc
- env: HAVE_AUBIO_DOUBLE=1 CFLAGS="-O3" WAFOPTS="--enable-fftw3"
+ env: HAVE_AUBIO_DOUBLE=1 CFLAGS="-O3" WAFOPTS="--enable-fftw3 --disable-avcodec"
- python: 2.7
os: linux
compiler: gcc
--- a/src/aubio_priv.h
+++ b/src/aubio_priv.h
@@ -324,6 +324,12 @@
#define isnan _isnan
#endif
+#if !defined(_MSC_VER)
+#define AUBIO_STRERROR(errno,buf,len) strerror_r(errno, buf, len)
+#else
+#define AUBIO_STRERROR(errno,buf,len) strerror_s(buf, len, errno)
+#endif
+
/* handy shortcuts */
#define DB2LIN(g) (POW(10.0,(g)*0.05f))
#define LIN2DB(v) (20.0*LOG10(v))
--- a/src/io/ioutils.c
+++ b/src/io/ioutils.c
@@ -19,6 +19,7 @@
*/
#include "aubio_priv.h"
+#include "fmat.h"
uint_t
aubio_io_validate_samplerate(const char_t *kind, const char_t *path, uint_t samplerate)
@@ -50,6 +51,75 @@
return AUBIO_FAIL;
}
return AUBIO_OK;
+}
+
+uint_t
+aubio_source_validate_input_length(const char_t *kind, const char_t *path,
+ uint_t hop_size, uint_t read_data_length)
+{
+ uint_t length = hop_size;
+ if (hop_size < read_data_length) {
+ AUBIO_WRN("%s: partial read from %s, trying to read %d frames, but"
+ " hop_size is %d\n", kind, path, read_data_length, hop_size);
+ } else if (hop_size > read_data_length) {
+ AUBIO_WRN("%s: partial read from %s, trying to read %d frames into"
+ " a buffer of length %d\n", kind, path, hop_size, read_data_length);
+ length = read_data_length;
+ }
+ return length;
+}
+
+uint_t
+aubio_source_validate_input_channels(const char_t *kind, const char_t *path,
+ uint_t source_channels, uint_t read_data_height)
+{
+ uint_t channels = source_channels;
+ if (read_data_height < source_channels) {
+ AUBIO_WRN("%s: partial read from %s, trying to read %d channels,"
+ " but found output of height %d\n", kind, path, source_channels,
+ read_data_height);
+ channels = read_data_height;
+ } else if (read_data_height > source_channels) {
+ // do not show a warning when trying to read into more channels than
+ // the input source.
+#if 0
+ AUBIO_WRN("%s: partial read from %s, trying to read %d channels,"
+ " but found output of height %d\n", kind, path, source_channels,
+ read_data_height);
+#endif
+ channels = source_channels;
+ }
+ return channels;
+}
+
+void
+aubio_source_pad_output (fvec_t *read_data, uint_t source_read)
+{
+ if (source_read < read_data->length) {
+ AUBIO_MEMSET(read_data->data + source_read, 0,
+ (read_data->length - source_read) * sizeof(smpl_t));
+ }
+}
+
+void
+aubio_source_pad_multi_output (fmat_t *read_data,
+ uint_t source_channels, uint_t source_read) {
+ uint_t i;
+ if (source_read < read_data->length) {
+ for (i = 0; i < read_data->height; i++) {
+ AUBIO_MEMSET(read_data->data[i] + source_read, 0,
+ (read_data->length - source_read) * sizeof(smpl_t));
+ }
+ }
+
+ // destination matrix has more channels than the file
+ // copy channels from the source to extra output channels
+ if (read_data->height > source_channels) {
+ for (i = source_channels; i < read_data->height; i++) {
+ AUBIO_MEMCPY(read_data->data[i], read_data->data[i % source_channels],
+ sizeof(smpl_t) * read_data->length);
+ }
+ }
}
uint_t
--- a/src/io/ioutils.h
+++ b/src/io/ioutils.h
@@ -53,12 +53,58 @@
uint_t aubio_io_validate_channels(const char_t *kind, const char_t *path,
uint_t channels);
-/** validate length of input
+/** validate length of source output
\param kind the object kind to report on
\param path the path to report on
+ \param hop_size number of frames to be read
+ \param read_data_length actual length of input
+
+ \return hop_size or the maximum number of frames that can be written
+*/
+uint_t
+aubio_source_validate_input_length(const char_t *kind, const char_t *path,
+ uint_t hop_size, uint_t read_data_length);
+
+/** validate height of source output
+
+ \param kind the object kind to report on
+ \param path the path to report on
+ \param source_channels maximum number of channels that can be written
+ \param read_data_height actual height of input
+
+ \return write_data_height or the maximum number of channels
+*/
+uint_t
+aubio_source_validate_input_channels(const char_t *kind, const char_t *path,
+ uint_t source_channels, uint_t read_data_height);
+
+/** pad end of source output vector with zeroes
+
+ \param read_data output vector to pad
+ \param source_read number of frames read
+
+*/
+void
+aubio_source_pad_output (fvec_t *read_data, uint_t source_read);
+
+/** pad end of source output matrix with zeroes
+
+ \param read_data output matrix to pad
+ \param source_channels number of channels in the source
+ \param source_read number of frames read
+
+*/
+void
+aubio_source_pad_multi_output (fmat_t *read_data, uint_t source_channels,
+ uint_t source_read);
+
+/** validate length of sink input
+
+ \param kind the object kind to report on
+ \param path the path to report on
\param max_size maximum number of frames that can be written
- \param write_data_length actual length of input vector/matrix
+ \param write_data_length actual length of input
\param write number of samples asked
\return write or the maximum number of frames that can be written
@@ -67,11 +113,11 @@
aubio_sink_validate_input_length(const char_t *kind, const char_t *path,
uint_t max_size, uint_t write_data_length, uint_t write);
-/** validate height of input
+/** validate height of sink input
\param kind the object kind to report on
\param path the path to report on
- \param max_size maximum number of channels that can be written
+ \param sink_channels maximum number of channels that can be written
\param write_data_height actual height of input matrix
\return write_data_height or the maximum number of channels
--- a/src/io/sink_vorbis.c
+++ b/src/io/sink_vorbis.c
@@ -36,7 +36,7 @@
#include <errno.h> // errno
#include <time.h> // time
-#define MAX_SIZE 2048
+#define MAX_SIZE 4096
struct _aubio_sink_vorbis_t {
FILE *fid; // file id
@@ -63,6 +63,8 @@
uint_t aubio_sink_vorbis_close (aubio_sink_vorbis_t *s);
void del_aubio_sink_vorbis (aubio_sink_vorbis_t *s);
+static uint_t aubio_sink_vorbis_write_page(aubio_sink_vorbis_t *s);
+
aubio_sink_vorbis_t * new_aubio_sink_vorbis (const char_t *uri,
uint_t samplerate)
{
@@ -117,8 +119,10 @@
s->fid = fopen((const char *)s->path, "wb");
if (!s->fid) {
- AUBIO_ERR("sink_vorbis: Error opening file %s (%s)\n",
- s->path, strerror(errno));
+ char errorstr[256];
+ AUBIO_STRERROR(errno, errorstr, sizeof(errorstr));
+ AUBIO_ERR("sink_vorbis: Error opening file \'%s\' (%s)\n",
+ s->path, errorstr);
return AUBIO_FAIL;
}
@@ -143,8 +147,6 @@
// write header
{
- int ret = 0;
- size_t wrote;
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
@@ -159,17 +161,8 @@
// make sure audio data will start on a new page
while (1)
{
- ret = ogg_stream_flush(&s->os, &s->og);
- if (ret==0) break;
- wrote = fwrite(s->og.header, 1, s->og.header_len, s->fid);
- ret = (wrote == (unsigned)s->og.header_len);
- wrote = fwrite(s->og.body, 1, s->og.body_len, s->fid);
- ret &= (wrote == (unsigned)s->og.body_len);
- if (ret == 0) {
- AUBIO_ERR("sink_vorbis: failed writing \'%s\' to disk (%s)\n",
- s->path, strerror(errno));
- return AUBIO_FAIL;
- }
+ if (!ogg_stream_flush(&s->os, &s->og)) break;
+ if (aubio_sink_vorbis_write_page(s)) return AUBIO_FAIL;
}
}
@@ -211,10 +204,27 @@
return s->channels;
}
-void aubio_sink_vorbis_write(aubio_sink_vorbis_t *s)
-{
+static
+uint_t aubio_sink_vorbis_write_page(aubio_sink_vorbis_t *s) {
int result;
size_t wrote;
+ wrote = fwrite(s->og.header, 1, s->og.header_len, s->fid);
+ result = (wrote == (unsigned)s->og.header_len);
+ wrote = fwrite(s->og.body, 1, s->og.body_len, s->fid);
+ result &= (wrote == (unsigned)s->og.body_len);
+ if (result == 0) {
+ char errorstr[256];
+ AUBIO_STRERROR(errno, errorstr, sizeof(errorstr));
+ AUBIO_ERR("sink_vorbis: failed writing \'%s\' to disk (%s)\n",
+ s->path, errorstr);
+ return AUBIO_FAIL;
+ }
+ return AUBIO_OK;
+}
+
+static
+void aubio_sink_vorbis_write(aubio_sink_vorbis_t *s)
+{
// pre-analysis
while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
@@ -226,16 +236,8 @@
ogg_stream_packetin(&s->os, &s->op);
while (1) {
- result = ogg_stream_pageout (&s->os, &s->og);
- if (result == 0) break;
- wrote = fwrite(s->og.header, 1, s->og.header_len, s->fid);
- result = (wrote == (unsigned)s->og.header_len);
- wrote = fwrite(s->og.body, 1, s->og.body_len, s->fid);
- result &= (wrote == (unsigned)s->og.body_len);
- if (result == 0) {
- AUBIO_WRN("sink_vorbis: failed writing \'%s\' to disk (%s)\n",
- s->path, strerror(errno));
- }
+ if (!ogg_stream_pageout (&s->os, &s->og)) break;
+ aubio_sink_vorbis_write_page(s);
if (ogg_page_eos(&s->og)) break;
}
}
@@ -290,7 +292,7 @@
}
}
// tell vorbis how many frames were written
- vorbis_analysis_wrote(&s->vd, (long)write);
+ vorbis_analysis_wrote(&s->vd, (long)length);
}
aubio_sink_vorbis_write(s);
@@ -305,8 +307,10 @@
aubio_sink_vorbis_write(s);
if (s->fid && fclose(s->fid)) {
- AUBIO_ERR("sink_vorbis: Error closing file %s (%s)\n",
- s->path, strerror(errno));
+ char errorstr[256];
+ AUBIO_STRERROR(errno, errorstr, sizeof(errorstr));
+ AUBIO_ERR("sink_vorbis: Error closing file \'%s\' (%s)\n",
+ s->path, errorstr);
return AUBIO_FAIL;
}
s->fid = NULL;
--- a/src/io/sink_wavwrite.c
+++ b/src/io/sink_wavwrite.c
@@ -162,55 +162,67 @@
uint_t aubio_sink_wavwrite_open(aubio_sink_wavwrite_t *s) {
unsigned char buf[5];
uint_t byterate, blockalign;
+ size_t written = 0;
/* open output file */
s->fid = fopen((const char *)s->path, "wb");
if (!s->fid) {
- AUBIO_ERR("sink_wavwrite: could not open %s (%s)\n", s->path, strerror(errno));
+ char errorstr[256];
+ AUBIO_STRERROR(errno, errorstr, sizeof(errorstr));
+ AUBIO_ERR("sink_wavwrite: could not open %s (%s)\n", s->path, errorstr);
goto beach;
}
// ChunkID
- fwrite("RIFF", 4, 1, s->fid);
+ written += fwrite("RIFF", 4, 1, s->fid);
// ChunkSize (0 for now, actual size will be written in _close)
- fwrite(write_little_endian(0, buf, 4), 4, 1, s->fid);
+ written += fwrite(write_little_endian(0, buf, 4), 4, 1, s->fid);
// Format
- fwrite("WAVE", 4, 1, s->fid);
+ written += fwrite("WAVE", 4, 1, s->fid);
// Subchunk1ID
- fwrite("fmt ", 4, 1, s->fid);
+ written += fwrite("fmt ", 4, 1, s->fid);
// Subchunk1Size
- fwrite(write_little_endian(16, buf, 4), 4, 1, s->fid);
+ written += fwrite(write_little_endian(16, buf, 4), 4, 1, s->fid);
// AudioFormat
- fwrite(write_little_endian(1, buf, 2), 2, 1, s->fid);
+ written += fwrite(write_little_endian(1, buf, 2), 2, 1, s->fid);
// NumChannels
- fwrite(write_little_endian(s->channels, buf, 2), 2, 1, s->fid);
+ written += fwrite(write_little_endian(s->channels, buf, 2), 2, 1, s->fid);
// SampleRate
- fwrite(write_little_endian(s->samplerate, buf, 4), 4, 1, s->fid);
+ written += fwrite(write_little_endian(s->samplerate, buf, 4), 4, 1, s->fid);
// ByteRate
byterate = s->samplerate * s->channels * s->bitspersample / 8;
- fwrite(write_little_endian(byterate, buf, 4), 4, 1, s->fid);
+ written += fwrite(write_little_endian(byterate, buf, 4), 4, 1, s->fid);
// BlockAlign
blockalign = s->channels * s->bitspersample / 8;
- fwrite(write_little_endian(blockalign, buf, 2), 2, 1, s->fid);
+ written += fwrite(write_little_endian(blockalign, buf, 2), 2, 1, s->fid);
// BitsPerSample
- fwrite(write_little_endian(s->bitspersample, buf, 2), 2, 1, s->fid);
+ written += fwrite(write_little_endian(s->bitspersample, buf, 2), 2, 1, s->fid);
// Subchunk2ID
- fwrite("data", 4, 1, s->fid);
+ written += fwrite("data", 4, 1, s->fid);
// Subchunk1Size (0 for now, actual size will be written in _close)
- fwrite(write_little_endian(0, buf, 4), 4, 1, s->fid);
+ written += fwrite(write_little_endian(0, buf, 4), 4, 1, s->fid);
+ // fwrite(*, *, 1, s->fid) was called 13 times, check success
+ if (written != 13) {
+ char errorstr[256];
+ AUBIO_STRERROR(errno, errorstr, sizeof(errorstr));
+ AUBIO_WRN("sink_wavwrite: writing header to %s failed, expected %d"
+ " write but got only %d (%s)\n", s->path, 13, written, errorstr);
+ return AUBIO_FAIL;
+ }
+
s->scratch_size = s->max_size * s->channels;
/* allocate data for de/interleaving reallocated when needed. */
if (s->scratch_size >= MAX_SIZE * AUBIO_MAX_CHANNELS) {
@@ -226,9 +238,24 @@
return AUBIO_FAIL;
}
+static
+void aubio_sink_wavwrite_write_frames(aubio_sink_wavwrite_t *s, uint_t write)
+{
+ uint_t written_frames = 0;
+ written_frames = fwrite(s->scratch_data, 2 * s->channels, write, s->fid);
+
+ if (written_frames != write) {
+ char errorstr[256];
+ AUBIO_STRERROR(errno, errorstr, sizeof(errorstr));
+ AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, but only %d"
+ " could be written (%s)\n", write, s->path, written_frames, errorstr);
+ }
+ s->total_frames_written += written_frames;
+}
+
void aubio_sink_wavwrite_do(aubio_sink_wavwrite_t *s, fvec_t * write_data, uint_t write){
- uint_t c = 0, i = 0, written_frames = 0;
+ uint_t c = 0, i = 0;
uint_t length = aubio_sink_validate_input_length("sink_wavwrite", s->path,
s->max_size, write_data->length, write);
@@ -237,18 +264,12 @@
s->scratch_data[i * s->channels + c] = HTOLES(FLOAT_TO_SHORT(write_data->data[i]));
}
}
- written_frames = fwrite(s->scratch_data, 2, length * s->channels, s->fid);
- if (written_frames != write) {
- AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, "
- "but only %d could be written\n", write, s->path, written_frames);
- }
- s->total_frames_written += written_frames;
- return;
+ aubio_sink_wavwrite_write_frames(s, length);
}
void aubio_sink_wavwrite_do_multi(aubio_sink_wavwrite_t *s, fmat_t * write_data, uint_t write){
- uint_t c = 0, i = 0, written_frames = 0;
+ uint_t c = 0, i = 0;
uint_t channels = aubio_sink_validate_input_channels("sink_wavwrite", s->path,
s->channels, write_data->height);
@@ -260,29 +281,32 @@
s->scratch_data[i * s->channels + c] = HTOLES(FLOAT_TO_SHORT(write_data->data[c][i]));
}
}
- written_frames = fwrite(s->scratch_data, 2, length * s->channels, s->fid);
- if (written_frames != write * s->channels) {
- AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, "
- "but only %d could be written\n", write, s->path, written_frames / s->channels);
- }
- s->total_frames_written += written_frames;
- return;
+ aubio_sink_wavwrite_write_frames(s, length);
}
uint_t aubio_sink_wavwrite_close(aubio_sink_wavwrite_t * s) {
uint_t data_size = s->total_frames_written * s->bitspersample * s->channels / 8;
unsigned char buf[5];
+ size_t written = 0, err = 0;
if (!s->fid) return AUBIO_FAIL;
// ChunkSize
- fseek(s->fid, 4, SEEK_SET);
- fwrite(write_little_endian(data_size + 36, buf, 4), 4, 1, s->fid);
+ err += fseek(s->fid, 4, SEEK_SET);
+ written += fwrite(write_little_endian(data_size + 36, buf, 4), 4, 1, s->fid);
// Subchunk2Size
- fseek(s->fid, 40, SEEK_SET);
- fwrite(write_little_endian(data_size, buf, 4), 4, 1, s->fid);
+ err += fseek(s->fid, 40, SEEK_SET);
+ written += fwrite(write_little_endian(data_size, buf, 4), 4, 1, s->fid);
+ if (written != 2 || err != 0) {
+ char errorstr[256];
+ AUBIO_STRERROR(errno, errorstr, sizeof(errorstr));
+ AUBIO_WRN("sink_wavwrite: updating header of %s failed, expected %d"
+ " write but got only %d (%s)\n", s->path, 2, written, errorstr);
+ }
// close file
if (fclose(s->fid)) {
- AUBIO_ERR("sink_wavwrite: Error closing file %s (%s)\n", s->path, strerror(errno));
+ char errorstr[256];
+ AUBIO_STRERROR(errno, errorstr, sizeof(errorstr));
+ AUBIO_ERR("sink_wavwrite: Error closing file %s (%s)\n", s->path, errorstr);
}
s->fid = NULL;
return AUBIO_OK;
--- a/src/io/source_apple_audio.c
+++ b/src/io/source_apple_audio.c
@@ -24,6 +24,7 @@
#include "fvec.h"
#include "fmat.h"
+#include "ioutils.h"
#include "io/source_apple_audio.h"
// ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ...
@@ -209,9 +210,13 @@
uint_t * read) {
uint_t c, v;
UInt32 loadedPackets = aubio_source_apple_audio_read_frame(s);
+ uint_t length = aubio_source_validate_input_length("source_apple_audio",
+ s->path, s->block_size, read_to->length);
smpl_t *data = (smpl_t*)s->bufferList.mBuffers[0].mData;
- for (v = 0; v < loadedPackets; v++) {
+ length = MIN(loadedPackets, length);
+
+ for (v = 0; v < length; v++) {
read_to->data[v] = 0.;
for (c = 0; c < s->channels; c++) {
read_to->data[v] += data[ v * s->channels + c];
@@ -219,46 +224,31 @@
read_to->data[v] /= (smpl_t)s->channels;
}
// short read, fill with zeros
- if (loadedPackets < s->block_size) {
- for (v = loadedPackets; v < s->block_size; v++) {
- read_to->data[v] = 0.;
- }
- }
+ aubio_source_pad_output(read_to, length);
- *read = (uint_t)loadedPackets;
- return;
+ *read = (uint_t)length;
}
void aubio_source_apple_audio_do_multi(aubio_source_apple_audio_t *s, fmat_t * read_to, uint_t * read) {
uint_t c, v;
+ uint_t length = aubio_source_validate_input_length("source_apple_audio",
+ s->path, s->block_size, read_to->length);
+ uint_t channels = aubio_source_validate_input_channels("source_apple_audio",
+ s->path, s->channels, read_to->height);
UInt32 loadedPackets = aubio_source_apple_audio_read_frame(s);
smpl_t *data = (smpl_t*)s->bufferList.mBuffers[0].mData;
- for (v = 0; v < loadedPackets; v++) {
- for (c = 0; c < read_to->height; c++) {
+ length = MIN(loadedPackets, length);
+
+ for (v = 0; v < length; v++) {
+ for (c = 0; c < channels; c++) {
read_to->data[c][v] = data[ v * s->channels + c];
}
}
- // if read_data has more channels than the file
- if (read_to->height > s->channels) {
- // copy last channel to all additional channels
- for (v = 0; v < loadedPackets; v++) {
- for (c = s->channels; c < read_to->height; c++) {
- read_to->data[c][v] = data[ v * s->channels + (s->channels - 1)];
- }
- }
- }
- // short read, fill with zeros
- if (loadedPackets < s->block_size) {
- for (v = loadedPackets; v < s->block_size; v++) {
- for (c = 0; c < read_to->height; c++) {
- read_to->data[c][v] = 0.;
- }
- }
- }
- *read = (uint_t)loadedPackets;
- return;
+ aubio_source_pad_multi_output(read_to, s->channels, (uint_t)length);
+
+ *read = (uint_t)length;
}
uint_t aubio_source_apple_audio_close (aubio_source_apple_audio_t *s)
--- a/src/io/source_avcodec.c
+++ b/src/io/source_avcodec.c
@@ -60,6 +60,7 @@
#include "aubio_priv.h"
#include "fvec.h"
#include "fmat.h"
+#include "ioutils.h"
#include "source_avcodec.h"
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(56, 56, 0)
@@ -488,8 +489,10 @@
uint_t i, j;
uint_t end = 0;
uint_t total_wrote = 0;
- while (total_wrote < s->hop_size) {
- end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
+ uint_t length = aubio_source_validate_input_length("source_avcodec", s->path,
+ s->hop_size, read_data->length);
+ while (total_wrote < length) {
+ end = MIN(s->read_samples - s->read_index, length - total_wrote);
for (i = 0; i < end; i++) {
read_data->data[i + total_wrote] = 0.;
for (j = 0; j < s->input_channels; j++) {
@@ -499,7 +502,7 @@
read_data->data[i + total_wrote] *= 1./s->input_channels;
}
total_wrote += end;
- if (total_wrote < s->hop_size) {
+ if (total_wrote < length) {
uint_t avcodec_read = 0;
aubio_source_avcodec_readframe(s, &avcodec_read);
s->read_samples = avcodec_read;
@@ -511,11 +514,9 @@
s->read_index += end;
}
}
- if (total_wrote < s->hop_size) {
- for (i = total_wrote; i < s->hop_size; i++) {
- read_data->data[i] = 0.;
- }
- }
+
+ aubio_source_pad_output(read_data, total_wrote);
+
*read = total_wrote;
}
@@ -524,9 +525,13 @@
uint_t i,j;
uint_t end = 0;
uint_t total_wrote = 0;
- while (total_wrote < s->hop_size) {
- end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
- for (j = 0; j < read_data->height; j++) {
+ uint_t length = aubio_source_validate_input_length("source_wavread", s->path,
+ s->hop_size, read_data->length);
+ uint_t channels = aubio_source_validate_input_channels("source_wavread",
+ s->path, s->input_channels, read_data->height);
+ while (total_wrote < length) {
+ end = MIN(s->read_samples - s->read_index, length - total_wrote);
+ for (j = 0; j < channels; j++) {
for (i = 0; i < end; i++) {
read_data->data[j][i + total_wrote] =
s->output[(i + s->read_index) * s->input_channels + j];
@@ -533,7 +538,7 @@
}
}
total_wrote += end;
- if (total_wrote < s->hop_size) {
+ if (total_wrote < length) {
uint_t avcodec_read = 0;
aubio_source_avcodec_readframe(s, &avcodec_read);
s->read_samples = avcodec_read;
@@ -545,13 +550,9 @@
s->read_index += end;
}
}
- if (total_wrote < s->hop_size) {
- for (j = 0; j < read_data->height; j++) {
- for (i = total_wrote; i < s->hop_size; i++) {
- read_data->data[j][i] = 0.;
- }
- }
- }
+
+ aubio_source_pad_multi_output(read_data, s->input_channels, total_wrote);
+
*read = total_wrote;
}
--- a/src/io/source_sndfile.c
+++ b/src/io/source_sndfile.c
@@ -26,6 +26,7 @@
#include "fvec.h"
#include "fmat.h"
+#include "ioutils.h"
#include "source_sndfile.h"
#include "temporal/resampler.h"
@@ -169,8 +170,13 @@
void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_data, uint_t * read){
uint_t i,j, input_channels = s->input_channels;
/* read from file into scratch_data */
- sf_count_t read_samples = aubio_sf_read_smpl (s->handle, s->scratch_data, s->scratch_size);
+ uint_t length = aubio_source_validate_input_length("source_sndfile", s->path,
+ s->hop_size, read_data->length);
+ sf_count_t read_samples = aubio_sf_read_smpl (s->handle, s->scratch_data,
+ s->input_channels * length);
+ length = MIN(read_samples / s->input_channels, length);
+
/* where to store de-interleaved data */
smpl_t *ptr_data;
#ifdef HAVE_SAMPLERATE
@@ -183,7 +189,7 @@
}
/* de-interleaving and down-mixing data */
- for (j = 0; j < read_samples / input_channels; j++) {
+ for (j = 0; j < length; j++) {
ptr_data[j] = 0;
for (i = 0; i < input_channels; i++) {
ptr_data[j] += s->scratch_data[input_channels*j+i];
@@ -197,13 +203,9 @@
}
#endif /* HAVE_SAMPLERATE */
- *read = (int)FLOOR(s->ratio * read_samples / input_channels + .5);
+ *read = (int)FLOOR(s->ratio * length + .5);
- if (*read < s->hop_size) {
- for (j = *read; j < s->hop_size; j++) {
- read_data->data[j] = 0;
- }
- }
+ aubio_source_pad_output (read_data, *read);
}
@@ -210,8 +212,15 @@
void aubio_source_sndfile_do_multi(aubio_source_sndfile_t * s, fmat_t * read_data, uint_t * read){
uint_t i,j, input_channels = s->input_channels;
/* do actual reading */
- sf_count_t read_samples = aubio_sf_read_smpl (s->handle, s->scratch_data, s->scratch_size);
+ uint_t length = aubio_source_validate_input_length("source_sndfile", s->path,
+ s->hop_size, read_data->length);
+ uint_t channels = aubio_source_validate_input_channels("source_sndfile",
+ s->path, s->input_channels, read_data->height);
+ sf_count_t read_samples = aubio_sf_read_smpl (s->handle, s->scratch_data,
+ length * s->input_channels);
+ length = MIN(read_samples / s->input_channels, length);
+
/* where to store de-interleaved data */
smpl_t **ptr_data;
#ifdef HAVE_SAMPLERATE
@@ -223,34 +232,12 @@
ptr_data = read_data->data;
}
- if (read_data->height < input_channels) {
- // destination matrix has less channels than the file; copy only first
- // channels of the file, de-interleaving data
- for (j = 0; j < read_samples / input_channels; j++) {
- for (i = 0; i < read_data->height; i++) {
- ptr_data[i][j] = s->scratch_data[j * input_channels + i];
- }
+ for (j = 0; j < length; j++) {
+ for (i = 0; i < channels; i++) {
+ ptr_data[i][j] = s->scratch_data[j * input_channels + i];
}
- } else {
- // destination matrix has as many or more channels than the file; copy each
- // channel from the file to the destination matrix, de-interleaving data
- for (j = 0; j < read_samples / input_channels; j++) {
- for (i = 0; i < input_channels; i++) {
- ptr_data[i][j] = s->scratch_data[j * input_channels + i];
- }
- }
}
- if (read_data->height > input_channels) {
- // destination matrix has more channels than the file; copy last channel
- // of the file to each additional channels, de-interleaving data
- for (j = 0; j < read_samples / input_channels; j++) {
- for (i = input_channels; i < read_data->height; i++) {
- ptr_data[i][j] = s->scratch_data[j * input_channels + (input_channels - 1)];
- }
- }
- }
-
#ifdef HAVE_SAMPLERATE
if (s->resamplers) {
for (i = 0; i < input_channels; i++) {
@@ -264,16 +251,9 @@
}
#endif /* HAVE_SAMPLERATE */
- *read = (int)FLOOR(s->ratio * read_samples / input_channels + .5);
+ *read = (int)FLOOR(s->ratio * length + .5);
- if (*read < s->hop_size) {
- for (i = 0; i < read_data->height; i++) {
- for (j = *read; j < s->hop_size; j++) {
- read_data->data[i][j] = 0.;
- }
- }
- }
-
+ aubio_source_pad_multi_output(read_data, input_channels, *read);
}
uint_t aubio_source_sndfile_get_samplerate(aubio_source_sndfile_t * s) {
--- a/src/io/source_wavread.c
+++ b/src/io/source_wavread.c
@@ -24,6 +24,7 @@
#include "fvec.h"
#include "fmat.h"
+#include "ioutils.h"
#include "source_wavread.h"
#include <errno.h>
@@ -347,13 +348,15 @@
uint_t i, j;
uint_t end = 0;
uint_t total_wrote = 0;
+ uint_t length = aubio_source_validate_input_length("source_wavread", s->path,
+ s->hop_size, read_data->length);
if (s->fid == NULL) {
AUBIO_ERR("source_wavread: could not read from %s (file not opened)\n",
s->path);
return;
}
- while (total_wrote < s->hop_size) {
- end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
+ while (total_wrote < length) {
+ end = MIN(s->read_samples - s->read_index, length - total_wrote);
for (i = 0; i < end; i++) {
read_data->data[i + total_wrote] = 0;
for (j = 0; j < s->input_channels; j++ ) {
@@ -362,7 +365,7 @@
read_data->data[i + total_wrote] /= (smpl_t)(s->input_channels);
}
total_wrote += end;
- if (total_wrote < s->hop_size) {
+ if (total_wrote < length) {
uint_t wavread_read = 0;
aubio_source_wavread_readframe(s, &wavread_read);
s->read_samples = wavread_read;
@@ -374,11 +377,9 @@
s->read_index += end;
}
}
- if (total_wrote < s->hop_size) {
- for (i = end; i < s->hop_size; i++) {
- read_data->data[i] = 0.;
- }
- }
+
+ aubio_source_pad_output (read_data, total_wrote);
+
*read = total_wrote;
}
@@ -386,20 +387,24 @@
uint_t i,j;
uint_t end = 0;
uint_t total_wrote = 0;
+ uint_t length = aubio_source_validate_input_length("source_wavread", s->path,
+ s->hop_size, read_data->length);
+ uint_t channels = aubio_source_validate_input_channels("source_wavread",
+ s->path, s->input_channels, read_data->height);
if (s->fid == NULL) {
AUBIO_ERR("source_wavread: could not read from %s (file not opened)\n",
s->path);
return;
}
- while (total_wrote < s->hop_size) {
- end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
- for (j = 0; j < read_data->height; j++) {
+ while (total_wrote < length) {
+ end = MIN(s->read_samples - s->read_index, length - total_wrote);
+ for (j = 0; j < channels; j++) {
for (i = 0; i < end; i++) {
read_data->data[j][i + total_wrote] = s->output->data[j][i];
}
}
total_wrote += end;
- if (total_wrote < s->hop_size) {
+ if (total_wrote < length) {
uint_t wavread_read = 0;
aubio_source_wavread_readframe(s, &wavread_read);
s->read_samples = wavread_read;
@@ -411,13 +416,9 @@
s->read_index += end;
}
}
- if (total_wrote < s->hop_size) {
- for (j = 0; j < read_data->height; j++) {
- for (i = end; i < s->hop_size; i++) {
- read_data->data[j][i] = 0.;
- }
- }
- }
+
+ aubio_source_pad_multi_output(read_data, s->input_channels, total_wrote);
+
*read = total_wrote;
}
--- a/tests/src/io/base-source_custom.h
+++ b/tests/src/io/base-source_custom.h
@@ -93,10 +93,46 @@
aubio_source_custom_do(s, vec, &read);
if (read != hop_size) return 1;
+ // read again in undersized vector
+ del_fvec(vec);
+ vec = new_fvec(hop_size - 1);
+ aubio_source_custom_do(s, vec, &read);
+ if (read != hop_size - 1) return 1;
+
+ // read again in oversized vector
+ del_fvec(vec);
+ vec = new_fvec(hop_size + 1);
+ aubio_source_custom_do(s, vec, &read);
+ if (read != hop_size) return 1;
+
// seek to 0
if(aubio_source_custom_seek(s, 0)) return 1;
// read again as multiple channels
+ aubio_source_custom_do_multi(s, mat, &read);
+ if (read != hop_size) return 1;
+
+ // read again as multiple channels in an undersized matrix
+ del_fmat(mat);
+ mat = new_fmat(channels - 1, hop_size);
+ aubio_source_custom_do_multi(s, mat, &read);
+ if (read != hop_size) return 1;
+
+ // read again as multiple channels in an undersized matrix
+ del_fmat(mat);
+ mat = new_fmat(channels, hop_size - 1);
+ aubio_source_custom_do_multi(s, mat, &read);
+ if (read != hop_size - 1) return 1;
+
+ // read again as multiple channels in an oversized matrix
+ del_fmat(mat);
+ mat = new_fmat(channels + 1, hop_size);
+ aubio_source_custom_do_multi(s, mat, &read);
+ if (read != hop_size) return 1;
+
+ // read again as multiple channels in an oversized matrix
+ del_fmat(mat);
+ mat = new_fmat(channels, hop_size + 1);
aubio_source_custom_do_multi(s, mat, &read);
if (read != hop_size) return 1;
--- a/tests/src/io/test-source.c
+++ b/tests/src/io/test-source.c
@@ -89,10 +89,46 @@
aubio_source_do(s, vec, &read);
if (read != hop_size) return 1;
+ // read again in undersized vector
+ del_fvec(vec);
+ vec = new_fvec(hop_size - 1);
+ aubio_source_do(s, vec, &read);
+ if (read != hop_size - 1) return 1;
+
+ // read again in oversized vector
+ del_fvec(vec);
+ vec = new_fvec(hop_size + 1);
+ aubio_source_do(s, vec, &read);
+ if (read != hop_size) return 1;
+
// seek to 0
if(aubio_source_seek(s, 0)) return 1;
// read again as multiple channels
+ aubio_source_do_multi(s, mat, &read);
+ if (read != hop_size) return 1;
+
+ // read again as multiple channels in an undersized matrix
+ del_fmat(mat);
+ mat = new_fmat(channels - 1, hop_size);
+ aubio_source_do_multi(s, mat, &read);
+ if (read != hop_size) return 1;
+
+ // read again as multiple channels in an undersized matrix
+ del_fmat(mat);
+ mat = new_fmat(channels, hop_size - 1);
+ aubio_source_do_multi(s, mat, &read);
+ if (read != hop_size - 1) return 1;
+
+ // read again as multiple channels in an oversized matrix
+ del_fmat(mat);
+ mat = new_fmat(channels + 1, hop_size);
+ aubio_source_do_multi(s, mat, &read);
+ if (read != hop_size) return 1;
+
+ // read again as multiple channels in an oversized matrix
+ del_fmat(mat);
+ mat = new_fmat(channels, hop_size + 1);
aubio_source_do_multi(s, mat, &read);
if (read != hop_size) return 1;