shithub: aubio

Download patch

ref: 2b208a897175d73958ceb929e97438bf282f627e
parent: dbad82cf21d8e6e18a1ce4d18364f96fb390e148
author: Paul Brossier <piem@piem.org>
date: Wed Dec 19 10:18:05 EST 2018

[io] sink_apple_audio can now write aiff, mp4, and aac

--- a/src/io/sink_apple_audio.c
+++ b/src/io/sink_apple_audio.c
@@ -38,6 +38,10 @@
 
 uint_t aubio_sink_apple_audio_open(aubio_sink_apple_audio_t *s);
 
+uint_t aubio_str_extension_matches(const char_t *ext,
+    const char_t *pattern);
+const char_t *aubio_str_get_extension(const char_t *filename);
+
 #define MAX_SIZE 4096 // the maximum number of frames that can be written at a time
 
 void aubio_sink_apple_audio_write(aubio_sink_apple_audio_t *s, uint_t write);
@@ -52,6 +56,7 @@
   AudioBufferList bufferList;
   ExtAudioFileRef audioFile;
   bool async;
+  AudioFileTypeID fileType;
 };
 
 aubio_sink_apple_audio_t * new_aubio_sink_apple_audio(const char_t * uri, uint_t samplerate) {
@@ -70,6 +75,8 @@
   s->samplerate = 0;
   s->channels = 0;
 
+  aubio_sink_apple_audio_preset_format(s, aubio_str_get_extension(uri));
+
   // zero samplerate given. do not open yet
   if ((sint_t)samplerate == 0) {
     return s;
@@ -120,6 +127,72 @@
   return AUBIO_OK;
 }
 
+uint_t aubio_sink_apple_audio_preset_format(aubio_sink_apple_audio_t *s,
+    const char_t *fmt)
+{
+  if (aubio_str_extension_matches(fmt, "wav")) {
+    s->fileType = kAudioFileWAVEType;
+  } else if (aubio_str_extension_matches(fmt, "m4a")
+      || aubio_str_extension_matches(fmt, "mp4") ) {
+    // use alac for "mp4" and "m4a"
+    s->fileType = kAudioFileM4AType;
+  } else if (aubio_str_extension_matches(fmt, "aac") ) {
+    // only use lossy codec for "aac"
+    s->fileType = kAudioFileMPEG4Type;
+  } else if (aubio_str_extension_matches(fmt, "aiff") ) {
+    // only use lossy codec for "aac"
+    s->fileType = kAudioFileAIFFType;
+  } else {
+    AUBIO_WRN("sink_apple_audio: could not guess format for %s,"
+       " using default (wav)\n", s->path);
+    s->fileType = kAudioFileWAVEType;
+    return AUBIO_FAIL;
+  }
+  return AUBIO_OK;
+}
+
+static void aubio_sink_apple_audio_set_client_format(aubio_sink_apple_audio_t* s,
+    AudioStreamBasicDescription *clientFormat)
+{
+  memset(clientFormat, 0, sizeof(AudioStreamBasicDescription));
+  // always set samplerate and channels first
+  clientFormat->mSampleRate       = (Float64)(s->samplerate);
+  clientFormat->mChannelsPerFrame = s->channels;
+
+  switch (s->fileType) {
+    case kAudioFileM4AType:
+      clientFormat->mFormatID         = kAudioFormatAppleLossless;
+      break;
+    case kAudioFileMPEG4Type:
+      clientFormat->mFormatID         = kAudioFormatMPEG4AAC;
+      clientFormat->mFormatFlags      = kMPEG4Object_AAC_Main;
+      clientFormat->mFormatFlags     |= kAppleLosslessFormatFlag_16BitSourceData;
+      clientFormat->mFramesPerPacket  = 1024;
+      break;
+    case kAudioFileWAVEType:
+      clientFormat->mFormatID         = kAudioFormatLinearPCM;
+      clientFormat->mFormatFlags      = kAudioFormatFlagIsSignedInteger;
+      clientFormat->mFormatFlags     |= kAudioFormatFlagIsPacked;
+      clientFormat->mBitsPerChannel   = sizeof(short) * 8;
+      clientFormat->mFramesPerPacket  = 1;
+      clientFormat->mBytesPerFrame    = clientFormat->mBitsPerChannel * clientFormat->mChannelsPerFrame / 8;
+      clientFormat->mBytesPerPacket   = clientFormat->mFramesPerPacket * clientFormat->mBytesPerFrame;
+      break;
+    case kAudioFileAIFFType:
+      clientFormat->mFormatID         = kAudioFormatLinearPCM;
+      clientFormat->mFormatFlags      = kAudioFormatFlagIsSignedInteger;
+      clientFormat->mFormatFlags     |= kAudioFormatFlagIsPacked;
+      clientFormat->mFormatFlags     |= kAudioFormatFlagIsBigEndian;
+      clientFormat->mBitsPerChannel   = sizeof(short) * 8;
+      clientFormat->mFramesPerPacket  = 1;
+      clientFormat->mBytesPerFrame    = clientFormat->mBitsPerChannel * clientFormat->mChannelsPerFrame / 8;
+      clientFormat->mBytesPerPacket   = clientFormat->mFramesPerPacket * clientFormat->mBytesPerFrame;
+      break;
+    default:
+      break;
+  }
+}
+
 uint_t aubio_sink_apple_audio_get_samplerate(const aubio_sink_apple_audio_t *s)
 {
   return s->samplerate;
@@ -134,19 +207,6 @@
 
   if (s->samplerate == 0 || s->channels == 0) return AUBIO_FAIL;
 
-  AudioStreamBasicDescription clientFormat;
-  memset(&clientFormat, 0, sizeof(AudioStreamBasicDescription));
-  clientFormat.mFormatID         = kAudioFormatLinearPCM;
-  clientFormat.mSampleRate       = (Float64)(s->samplerate);
-  clientFormat.mFormatFlags      = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
-  clientFormat.mChannelsPerFrame = s->channels;
-  clientFormat.mBitsPerChannel   = sizeof(short) * 8;
-  clientFormat.mFramesPerPacket  = 1;
-  clientFormat.mBytesPerFrame    = clientFormat.mBitsPerChannel * clientFormat.mChannelsPerFrame / 8;
-  clientFormat.mBytesPerPacket   = clientFormat.mFramesPerPacket * clientFormat.mBytesPerFrame;
-  clientFormat.mReserved         = 0;
-
-  AudioFileTypeID fileType = kAudioFileWAVEType;
   CFURLRef fileURL = createURLFromPath(s->path);
   bool overwrite = true;
 
@@ -161,8 +221,13 @@
   inputFormat.mFramesPerPacket  = 1;
   inputFormat.mBytesPerFrame    = inputFormat.mBitsPerChannel * inputFormat.mChannelsPerFrame / 8;
   inputFormat.mBytesPerPacket   = inputFormat.mFramesPerPacket * inputFormat.mBytesPerFrame;
+
+  // get the in-file format
+  AudioStreamBasicDescription clientFormat;
+  aubio_sink_apple_audio_set_client_format(s, &clientFormat);
+
   OSStatus err = noErr;
-  err = ExtAudioFileCreateWithURL(fileURL, fileType, &clientFormat, NULL,
+  err = ExtAudioFileCreateWithURL(fileURL, s->fileType, &clientFormat, NULL,
      overwrite ? kAudioFileFlags_EraseFile : 0, &s->audioFile);
   CFRelease(fileURL);
   if (err) {
--- a/src/io/sink_apple_audio.h
+++ b/src/io/sink_apple_audio.h
@@ -96,6 +96,29 @@
 
 /**
 
+  preset sink format
+
+  \param s sink, created with ::new_aubio_sink_apple_audio
+  \param fmt format of the file to create
+
+  \return 0 on success, 1 on error
+
+  Preset the format of the sink. Supported format strings:
+   - "wav": WAVE, 16 bit (default)
+   - "aiff": AIFF, 16 bit
+   - "m4a" or "mp4": Apple Audio Lossless Codec (ALAC)
+   - "aac": Audio Advanced Codec, lossy
+
+  Full list of supported encoding format is available in Table 1-2 of
+  `Multimedia Programming Guide
+  <https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html>`_.
+
+ */
+uint_t aubio_sink_apple_audio_preset_format(aubio_sink_apple_audio_t *s,
+    const char_t *fmt);
+
+/**
+
   get samplerate of sink object
 
   \param s sink object, created with ::new_aubio_sink_apple_audio