From 4865e4b220200bd82eac01c42a57c3386f05ed0f Mon Sep 17 00:00:00 2001 From: Paul Brossier Date: Thu, 21 Mar 2013 20:29:19 -0500 Subject: [PATCH] src/io/source*: add _do_multi and _get_channels, really downmix apple_audio --- src/io/source.c | 21 +++++++++++++ src/io/source.h | 24 +++++++++++++++ src/io/source_apple_audio.c | 50 ++++++++++++++++++++++++++----- src/io/source_apple_audio.h | 24 +++++++++++++++ src/io/source_sndfile.c | 40 ++++++++++++++++++++++++- src/io/source_sndfile.h | 10 +++++++ tests/src/io/test-source.c | 2 +- tests/src/io/test-source_multi.c | 51 ++++++++++++++++++++++++++++++++ 8 files changed, 213 insertions(+), 9 deletions(-) create mode 100644 tests/src/io/test-source_multi.c diff --git a/src/io/source.c b/src/io/source.c index 5e932913..7bce2e0c 100644 --- a/src/io/source.c +++ b/src/io/source.c @@ -21,6 +21,7 @@ #include "config.h" #include "aubio_priv.h" #include "fvec.h" +#include "fmat.h" #include "io/source.h" #ifdef __APPLE__ #include "io/source_apple_audio.h" @@ -59,6 +60,16 @@ void aubio_source_do(aubio_source_t * s, fvec_t * data, uint_t * read) { #endif /* __APPLE__ */ } +void aubio_source_do_multi(aubio_source_t * s, fmat_t * data, uint_t * read) { +#ifdef __APPLE__ + aubio_source_apple_audio_do_multi((aubio_source_apple_audio_t *)s->source, data, read); +#else /* __APPLE__ */ +#if HAVE_SNDFILE + aubio_source_sndfile_do_multi((aubio_source_sndfile_t *)s->source, data, read); +#endif /* HAVE_SNDFILE */ +#endif /* __APPLE__ */ +} + void del_aubio_source(aubio_source_t * s) { if (!s) return; #ifdef __APPLE__ @@ -81,6 +92,16 @@ uint_t aubio_source_get_samplerate(aubio_source_t * s) { #endif /* __APPLE__ */ } +uint_t aubio_source_get_channels(aubio_source_t * s) { +#ifdef __APPLE__ + return aubio_source_apple_audio_get_channels((aubio_source_apple_audio_t *)s->source); +#else /* __APPLE__ */ +#if HAVE_SNDFILE + return aubio_source_sndfile_get_channels((aubio_source_sndfile_t *)s->source); +#endif /* HAVE_SNDFILE */ +#endif /* __APPLE__ */ +} + uint_t aubio_source_seek (aubio_source_t * s, uint_t seek ) { #ifdef __APPLE__ return aubio_source_apple_audio_seek ((aubio_source_apple_audio_t *)s->source, seek); diff --git a/src/io/source.h b/src/io/source.h index d8ef74ec..c07bf1e5 100644 --- a/src/io/source.h +++ b/src/io/source.h @@ -67,6 +67,20 @@ aubio_source_t * new_aubio_source(char_t * uri, uint_t samplerate, uint_t hop_si */ void aubio_source_do(aubio_source_t * s, fvec_t * read_to, uint_t * read); +/** + + read polyphonic vector of length hop_size from source object + + \param s source object, created with ::new_aubio_source + \param read_to ::fmat_t of data to read to + \param read upon returns, equals to number of frames actually read + + Upon returns, `read` contains the number of frames actually read from the + source. `hop_size` if enough frames could be read, less otherwise. + +*/ +void aubio_source_do_multi(aubio_source_t * s, fmat_t * read_to, uint_t * read); + /** get samplerate of source object @@ -77,6 +91,16 @@ void aubio_source_do(aubio_source_t * s, fvec_t * read_to, uint_t * read); */ uint_t aubio_source_get_samplerate(aubio_source_t * s); +/** + + get channels of source object + + \param s source object, created with ::new_aubio_source + \return channels + +*/ +uint_t aubio_source_get_channels (aubio_source_t * s); + /** seek source object diff --git a/src/io/source_apple_audio.c b/src/io/source_apple_audio.c index fb310bfd..5040fe6f 100644 --- a/src/io/source_apple_audio.c +++ b/src/io/source_apple_audio.c @@ -22,6 +22,7 @@ #include "config.h" #include "aubio_priv.h" #include "fvec.h" +#include "fmat.h" #include "io/source_apple_audio.h" // ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ... @@ -56,7 +57,6 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t s->path = path; s->block_size = block_size; - s->channels = 1; OSStatus err = noErr; UInt32 propSize; @@ -82,6 +82,7 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t } s->samplerate = samplerate; s->source_samplerate = fileFormat.mSampleRate; + s->channels = fileFormat.mChannelsPerFrame; AudioStreamBasicDescription clientFormat; propSize = sizeof(clientFormat); @@ -99,9 +100,9 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t // set the client format description err = ExtAudioFileSetProperty(s->audioFile, kExtAudioFileProperty_ClientDataFormat, propSize, &clientFormat); - if (err) { AUBIO_ERROR("error in ExtAudioFileSetProperty, %d\n", (int)err); goto beach;} - -#if 0 + if (err) { + AUBIO_ERROR("error in ExtAudioFileSetProperty, %d\n", (int)err); +#if 1 // print client and format descriptions AUBIO_DBG("Opened %s\n", s->path); AUBIO_DBG("file/client Format.mFormatID: : %3c%c%c%c / %c%c%c%c\n", @@ -118,6 +119,8 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t AUBIO_DBG("file/client Format.mBytesPerPacket : %6d / %d\n", (int)fileFormat.mBytesPerPacket , (int)clientFormat.mBytesPerPacket); AUBIO_DBG("file/client Format.mReserved : %6d / %d\n", (int)fileFormat.mReserved , (int)clientFormat.mReserved); #endif + goto beach; + } // compute the size of the segments needed to read the input file UInt32 samples = s->block_size * clientFormat.mChannelsPerFrame; @@ -128,7 +131,7 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * path, uint_t } else if (rateRatio > 1.) { AUBIO_WRN("up-sampling %s from %0.2fHz to %0.2fHz\n", s->path, fileFormat.mSampleRate, clientFormat.mSampleRate); } else { - assert (segmentSize == samples ); + assert ( segmentSize == samples ); //AUBIO_DBG("not resampling, segmentSize %d, block_size %d\n", segmentSize, s->block_size); } @@ -172,6 +175,35 @@ beach: return; } +void aubio_source_apple_audio_do_multi(aubio_source_apple_audio_t *s, fmat_t * read_to, uint_t * read) { + UInt32 c, v, loadedPackets = s->block_size; + OSStatus err = ExtAudioFileRead(s->audioFile, &loadedPackets, &s->bufferList); + if (err) { AUBIO_ERROR("source_apple_audio: error in ExtAudioFileRead, %d\n", (int)err); goto beach;} + + short *data = (short*)s->bufferList.mBuffers[0].mData; + + smpl_t **buf = read_to->data; + + for (v = 0; v < loadedPackets; v++) { + for (c = 0; c < s->channels; c++) { + buf[c][v] = SHORT_TO_FLOAT(data[ v * s->channels + c]); + } + } + // short read, fill with zeros + if (loadedPackets < s->block_size) { + for (v = loadedPackets; v < s->block_size; v++) { + for (c = 0; c < s->channels; c++) { + buf[c][v] = 0.; + } + } + } + *read = (uint_t)loadedPackets; + return; +beach: + *read = 0; + return; +} + void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s){ OSStatus err = noErr; if (!s || !s->audioFile) { return; } @@ -184,8 +216,8 @@ void del_aubio_source_apple_audio(aubio_source_apple_audio_t * s){ } uint_t aubio_source_apple_audio_seek (aubio_source_apple_audio_t * s, uint_t pos) { - Float64 ratio = (Float64)(s->source_samplerate) / (Float64)(s->samplerate); - OSStatus err = ExtAudioFileSeek(s->audioFile, pos); + SInt64 resampled_pos = (SInt64)ROUND( pos * s->source_samplerate * 1. / s->samplerate ); + OSStatus err = ExtAudioFileSeek(s->audioFile, resampled_pos); if (err) AUBIO_ERROR("source_apple_audio: error in ExtAudioFileSeek (%d)\n", (int)err); return err; } @@ -194,4 +226,8 @@ uint_t aubio_source_apple_audio_get_samplerate(aubio_source_apple_audio_t * s) { return s->samplerate; } +uint_t aubio_source_apple_audio_get_channels(aubio_source_apple_audio_t * s) { + return s->channels; +} + #endif /* __APPLE__ */ diff --git a/src/io/source_apple_audio.h b/src/io/source_apple_audio.h index ee2c625b..03ed750d 100644 --- a/src/io/source_apple_audio.h +++ b/src/io/source_apple_audio.h @@ -73,6 +73,20 @@ aubio_source_apple_audio_t * new_aubio_source_apple_audio(char_t * uri, uint_t s */ void aubio_source_apple_audio_do(aubio_source_apple_audio_t * s, fvec_t * read_to, uint_t * read); +/** + + read polyphonic vector of length hop_size from source object + + \param s source object, created with ::new_aubio_source_apple_audio + \param read_to ::fmat_t of data to read to + \param read upon returns, equals to number of frames actually read + + Upon returns, `read` contains the number of frames actually read from the + source. `hop_size` if enough frames could be read, less otherwise. + +*/ +void aubio_source_apple_audio_do_multi(aubio_source_apple_audio_t * s, fmat_t * read_to, uint_t * read); + /** get samplerate of source object @@ -83,6 +97,16 @@ void aubio_source_apple_audio_do(aubio_source_apple_audio_t * s, fvec_t * read_t */ uint_t aubio_source_apple_audio_get_samplerate(aubio_source_apple_audio_t * s); +/** + + get channels of source object + + \param s source object, created with ::new_aubio_source_apple_audio + \return number of channels + +*/ +uint_t aubio_source_apple_audio_get_channels(aubio_source_apple_audio_t * s); + /** seek source object diff --git a/src/io/source_sndfile.c b/src/io/source_sndfile.c index a21cf606..cbd682b2 100644 --- a/src/io/source_sndfile.c +++ b/src/io/source_sndfile.c @@ -158,7 +158,7 @@ void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_data, uin for (j = 0; j < read_samples / input_channels; j++) { data[j] = 0; for (i = 0; i < input_channels; i++) { - data[j] += (smpl_t)s->scratch_data[input_channels*j+i]; + data[j] += s->scratch_data[input_channels*j+i]; } data[j] /= (smpl_t)input_channels; } @@ -172,10 +172,48 @@ void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_data, uin *read = (int)FLOOR(s->ratio * read_samples / input_channels + .5); } +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 = sf_read_float (s->handle, s->scratch_data, s->scratch_size); + + smpl_t **data; + +#ifdef HAVE_SAMPLERATE + if (s->ratio != 1) { + AUBIO_ERR("source_sndfile: no multi channel resampling yet"); + return; + data = s->input_data->data; + } else +#endif /* HAVE_SAMPLERATE */ + { + data = read_data->data; + } + + /* de-interleaving data */ + for (j = 0; j < read_samples / input_channels; j++) { + for (i = 0; i < input_channels; i++) { + data[i][j] = (smpl_t)s->scratch_data[input_channels*j+i]; + } + } + +#ifdef HAVE_SAMPLERATE + if (s->resampler) { + aubio_resampler_do(s->resampler, s->input_data, read_data); + } +#endif /* HAVE_SAMPLERATE */ + + *read = (int)FLOOR(s->ratio * read_samples / input_channels + .5); +} + uint_t aubio_source_sndfile_get_samplerate(aubio_source_sndfile_t * s) { return s->samplerate; } +uint_t aubio_source_sndfile_get_channels(aubio_source_sndfile_t * s) { + return s->input_channels; +} + uint_t aubio_source_sndfile_seek (aubio_source_sndfile_t * s, uint_t pos) { uint_t resampled_pos = (uint_t)ROUND(pos * s->input_samplerate * 1. / s->samplerate); return sf_seek (s->handle, resampled_pos, SEEK_SET); diff --git a/src/io/source_sndfile.h b/src/io/source_sndfile.h index 3aec3291..8dd10ac9 100644 --- a/src/io/source_sndfile.h +++ b/src/io/source_sndfile.h @@ -82,6 +82,16 @@ void aubio_source_sndfile_do(aubio_source_sndfile_t * s, fvec_t * read_to, uint_ */ uint_t aubio_source_sndfile_get_samplerate(aubio_source_sndfile_t * s); +/** + + get number of channels of source object + + \param s source object, created with ::new_aubio_source_sndfile + \return number of channels + +*/ +uint_t aubio_source_sndfile_get_channels (aubio_source_sndfile_t * s); + /** seek source object diff --git a/tests/src/io/test-source.c b/tests/src/io/test-source.c index 342ef406..76747e2d 100644 --- a/tests/src/io/test-source.c +++ b/tests/src/io/test-source.c @@ -36,7 +36,7 @@ int main (int argc, char **argv) do { aubio_source_do(s, vec, &read); - // fvec_print (vec); + fvec_print (vec); n_frames += read; } while ( read == hop_size ); diff --git a/tests/src/io/test-source_multi.c b/tests/src/io/test-source_multi.c new file mode 100644 index 00000000..a1a72ecc --- /dev/null +++ b/tests/src/io/test-source_multi.c @@ -0,0 +1,51 @@ +#include +#include "utils_tests.h" + +int main (int argc, char **argv) +{ + sint_t err = 0; + if (argc < 2) { + err = -2; + PRINT_ERR("not enough arguments\n"); + PRINT_MSG("read a wave file as a mono vector\n"); + PRINT_MSG("usage: %s [samplerate] [hop_size]\n", argv[0]); + PRINT_MSG("examples:\n"); + PRINT_MSG(" - read file.wav at original samplerate\n"); + PRINT_MSG(" %s file.wav\n", argv[0]); + PRINT_MSG(" - read file.wav at 32000Hz\n"); + PRINT_MSG(" %s file.aif 32000\n", argv[0]); + PRINT_MSG(" - read file.wav at original samplerate with 4096 blocks\n"); + PRINT_MSG(" %s file.wav 0 4096 \n", argv[0]); + return err; + } + + uint_t samplerate = 0; + uint_t hop_size = 256; + uint_t n_frames = 0, read = 0; + if ( argc == 3 ) samplerate = atoi(argv[2]); + if ( argc == 4 ) hop_size = atoi(argv[3]); + + char_t *source_path = argv[1]; + + aubio_source_t* s = new_aubio_source(source_path, samplerate, hop_size); + if (!s) { err = -1; goto beach; } + + if (samplerate == 0 ) samplerate = aubio_source_get_samplerate(s); + + fmat_t *mat = new_fmat(hop_size, aubio_source_get_channels(s) ); + + do { + aubio_source_do_multi (s, mat, &read); + fmat_print (mat); + n_frames += read; + } while ( read == hop_size ); + + PRINT_MSG("read %d frames at %dHz (%d blocks) from %s\n", n_frames, samplerate, + n_frames / hop_size, source_path); + + del_aubio_source (s); +beach: + del_fmat (mat); + + return err; +} -- 2.26.2