From 7b5e1a5cb8dbcf879fca6c4ad6ab3f7dfaf088d8 Mon Sep 17 00:00:00 2001 From: Paul Brossier Date: Wed, 19 Dec 2018 14:24:41 +0100 Subject: [PATCH] [io] sink_apple_audio to use native format conversion The important trick here is setting mDataByteSize to the actual number of frames to be written, as mentionned by James McCartney in [0]. [0]:https://www.mail-archive.com/coreaudio-api@lists.apple.com/msg01109.html --- src/io/sink_apple_audio.c | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/io/sink_apple_audio.c b/src/io/sink_apple_audio.c index 3a8524df..c58a52c6 100644 --- a/src/io/sink_apple_audio.c +++ b/src/io/sink_apple_audio.c @@ -31,9 +31,7 @@ // ExtAudioFileRef, AudioStreamBasicDescription, AudioBufferList, ... #include -#define FLOAT_TO_SHORT(x) (short)(x * 32768) - -extern int createAubioBufferList(AudioBufferList *bufferList, int channels, int segmentSize); +extern int createAudioBufferList(AudioBufferList *bufferList, int channels, int segmentSize); extern void freeAudioBufferList(AudioBufferList *bufferList); extern CFURLRef createURLFromPath(const char * path); char_t *getPrintableOSStatusError(char_t *str, OSStatus error); @@ -76,6 +74,7 @@ aubio_sink_apple_audio_t * new_aubio_sink_apple_audio(const char_t * uri, uint_t if ((sint_t)samplerate == 0) { return s; } + // invalid samplerate given, abort if (aubio_io_validate_samplerate("sink_apple_audio", s->path, samplerate)) { goto beach; @@ -150,6 +149,18 @@ uint_t aubio_sink_apple_audio_open(aubio_sink_apple_audio_t *s) { AudioFileTypeID fileType = kAudioFileWAVEType; CFURLRef fileURL = createURLFromPath(s->path); bool overwrite = true; + + // set the in-memory format + AudioStreamBasicDescription inputFormat; + memset(&inputFormat, 0, sizeof(AudioStreamBasicDescription)); + inputFormat.mFormatID = kAudioFormatLinearPCM; + inputFormat.mSampleRate = (Float64)(s->samplerate); + inputFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked; + inputFormat.mChannelsPerFrame = s->channels; + inputFormat.mBitsPerChannel = sizeof(smpl_t) * 8; + inputFormat.mFramesPerPacket = 1; + inputFormat.mBytesPerFrame = inputFormat.mBitsPerChannel * inputFormat.mChannelsPerFrame / 8; + inputFormat.mBytesPerPacket = inputFormat.mFramesPerPacket * inputFormat.mBytesPerFrame; OSStatus err = noErr; err = ExtAudioFileCreateWithURL(fileURL, fileType, &clientFormat, NULL, overwrite ? kAudioFileFlags_EraseFile : 0, &s->audioFile); @@ -161,7 +172,18 @@ uint_t aubio_sink_apple_audio_open(aubio_sink_apple_audio_t *s) { getPrintableOSStatusError(errorstr, err)); goto beach; } - if (createAubioBufferList(&s->bufferList, s->channels, s->max_frames * s->channels)) { + + err = ExtAudioFileSetProperty(s->audioFile, + kExtAudioFileProperty_ClientDataFormat, + sizeof(AudioStreamBasicDescription), &inputFormat); + if (err) { + char_t errorstr[20]; + AUBIO_ERR("sink_apple_audio: error when trying to set output format on %s " + "(%s)\n", s->path, getPrintableOSStatusError(errorstr, err)); + goto beach; + } + + if (createAudioBufferList(&s->bufferList, s->channels, s->max_frames * s->channels)) { AUBIO_ERR("sink_apple_audio: error when creating buffer list for %s, " "out of memory? \n", s->path); goto beach; @@ -174,13 +196,13 @@ beach: void aubio_sink_apple_audio_do(aubio_sink_apple_audio_t * s, fvec_t * write_data, uint_t write) { UInt32 c, v; - short *data = (short*)s->bufferList.mBuffers[0].mData; + smpl_t *data = (smpl_t*)s->bufferList.mBuffers[0].mData; uint_t length = aubio_sink_validate_input_length("sink_apple_audio", s->path, s->max_frames, write_data->length, write); for (c = 0; c < s->channels; c++) { for (v = 0; v < length; v++) { - data[v * s->channels + c] = FLOAT_TO_SHORT(write_data->data[v]); + data[v * s->channels + c] = write_data->data[v]; } } @@ -189,7 +211,7 @@ void aubio_sink_apple_audio_do(aubio_sink_apple_audio_t * s, fvec_t * write_data void aubio_sink_apple_audio_do_multi(aubio_sink_apple_audio_t * s, fmat_t * write_data, uint_t write) { UInt32 c, v; - short *data = (short*)s->bufferList.mBuffers[0].mData; + smpl_t *data = (smpl_t*)s->bufferList.mBuffers[0].mData; uint_t channels = aubio_sink_validate_input_channels("sink_apple_audio", s->path, s->channels, write_data->height); uint_t length = aubio_sink_validate_input_length("sink_apple_audio", s->path, @@ -197,7 +219,7 @@ void aubio_sink_apple_audio_do_multi(aubio_sink_apple_audio_t * s, fmat_t * writ for (c = 0; c < channels; c++) { for (v = 0; v < length; v++) { - data[v * s->channels + c] = FLOAT_TO_SHORT(write_data->data[c][v]); + data[v * s->channels + c] = write_data->data[c][v]; } } @@ -206,6 +228,10 @@ void aubio_sink_apple_audio_do_multi(aubio_sink_apple_audio_t * s, fmat_t * writ void aubio_sink_apple_audio_write(aubio_sink_apple_audio_t *s, uint_t write) { OSStatus err = noErr; + // set mDataByteSize to match the number of frames to be written + // see https://www.mail-archive.com/coreaudio-api@lists.apple.com/msg01109.html + s->bufferList.mBuffers[0].mDataByteSize = write * s->channels + * sizeof(smpl_t); if (s->async) { err = ExtAudioFileWriteAsync(s->audioFile, write, &s->bufferList); if (err) { -- 2.11.0