2

I'm experimenting with writing a simplistic single-AU play-through based, (almost)-no-latency tracking phase vocoder prototype in C. It's a standalone program. I want to find how much processing load can a single render callback safely bear, so I prefer keeping off async DSP.

My concept is to have only one pre-determined value which is window step, or hop size or decimation factor (different names for same term used in different literature sources). This number would equal inNumberFrames, which somehow depends on the device sampling rate (and what else?). All other parameters, such as window size and FFT size would be set in relation to the window step. This seems the simplest method for keeipng everything inside one callback.

Is there a safe method to machine-independently and safely guess or query which could be the inNumberFrames before the actual rendering starts, i.e. before calling AudioOutputUnitStart()?

The phase vocoder algorithm is mostly standard and very simple, using vDSP functions for FFT, plus custom phase integration and I have no problems with it.

Additional debugging info

This code is monitoring timings within the input callback:

static Float64 prev_stime;  //prev. sample time
static UInt64  prev_htime;  //prev. host time        
printf("inBus: %d\tframes: %d\tHtime: %lld\tStime: %7.2lf\n",
       (unsigned int)inBusNumber,
       (unsigned int)inNumberFrames,
       inTimeStamp->mHostTime   - prev_htime,
       inTimeStamp->mSampleTime - prev_stime);
prev_htime = inTimeStamp->mHostTime;
prev_stime = inTimeStamp->mSampleTime;

Curious enough, the argument inTimeStamp->mSampleTime actually shows the number of rendered frames (name of the argument seems somewhat misguiding). This number is always 512, no matter if another sampling rate has been re-set through AudioMIDISetup.app at runtime, as if the value had been programmatically hard-coded. On one hand, the

inTimeStamp->mHostTime - prev_htime

interval gets dynamically changed depending on the sampling rate set in a mathematically clear way. As long as sampling rate values match multiples of 44100Hz, actual rendering is going on. On the other hand 48kHz multiples produce the rendering error -10863 ( = kAudioUnitErr_CannotDoInCurrentContext ). I must have missed a very important point.

user3078414
  • 1,942
  • 2
  • 16
  • 24

3 Answers3

1

Assuming audioUnit is an input audio unit:

UInt32 inNumberFrames = 0;
UInt32 propSize = sizeof(UInt32);
AudioUnitGetProperty(audioUnit, 
                     kAudioDevicePropertyBufferFrameSize, 
                     kAudioUnitScope_Global, 
                     0, 
                     &inNumberFrames, 
                     &propSize);
rocky
  • 3,521
  • 1
  • 23
  • 31
  • It is a kAudioUnitSubType_HALOutput. I'll immediately check if your suggestion works for me. Thanks. – user3078414 Mar 08 '16 at 20:14
  • It returns the expected number. Since most of my code so far is "hacked" to meet this expectation, I have to rewrite it with _variables_, then check with other _sampling frequencies_, hosts and hardware devices. If it works, I'll accept your answer. So far it points in good direction. – user3078414 Mar 08 '16 at 20:23
  • The proposed code snippet always seems to return 512 frames, which seems ok for 44k1 SR. However, if I change the SR to 48k in **AudioMIDI setup** (which the program accepts), the expected `inNumberFrames` still stays the same (which I doubt it should), and the callback reports the `-10863 (= input device not present) error`. In the callback, also the actual `inNumberFrames` stays `512`, which I also doubt it should. – user3078414 Mar 11 '16 at 10:46
1

The number of frames is usually the sample rate times the buffer duration. There is an Audio Unit API to request a sample rate and a preferred buffer duration (such as 44100 and 5.8 mS resulting in 256 frames), but not all hardware on all OS versions honors all requested buffer durations or sample rates.

hotpaw2
  • 70,107
  • 14
  • 90
  • 153
  • Thanks. Can you please pass me more reference, please? Which version of which AU API are you mentioning? I understand _sample rate_ is a `Float64` (with a 56-bit mantissa), which allows for all kind of fractional rates and conversions in theory, but that's not what I'm after. I only need few standard rates (multiples of 44k1 and 48k), also `inNumberFrames` which are power-of-twos. I've also read that `inNumberFrames` can only be predicted to a certain degree, because the system may occasionally decide this number to be few frames more or less, although I haven't experienced it so far. – user3078414 Mar 09 '16 at 09:06
  • To whom it may concern: please see the follow-up to this question, for further elaboration and relevant answer: http://stackoverflow.com/questions/36546518/osx-coreaudio-api-for-setting-io-buffer-length – user3078414 Apr 11 '16 at 17:37
0

This number would equal inNumberFrames, which somehow depends on the device sampling rate (and what else?)

It depends on what you attempt to set it to. You can set it.

// attempt to set duration
NSTimeInterval _preferredDuration = ...
NSError* err;
[[AVAudioSession sharedInstance]setPreferredIOBufferDuration:_preferredDuration error:&err];


// now get the actual duration it uses

NSTimeInterval _actualBufferDuration;
_actualBufferDuration = [[AVAudioSession sharedInstance] IOBufferDuration];

It would use a value roughly around the preferred value you set. The actual value used is a time interval based on a power of 2 and the current sample rate.

If you are looking for consistency across devices, choose a value around 10ms. The worst performing reasonable modern device is iOS iPod touch 16gb without the rear facing camera. However, this device can do around 10ms callbacks with no problem. On some devices, you "can" set the duration quite low and get very fast callbacks, but often times it will crackle up because the processing is not finished in the callback before the next callback happens.

jaybers
  • 1,991
  • 13
  • 18
  • Thanks, however I just don't do anything with `AVAudioSession` API, nor `iOS`, nor `Cocoa`, only with OSX CoreAudio, which is a **C** API. So your API suggestions are off-limits to me. I hope my question was accurately worded. I hope having put OSX to the title for a reason. I must check now if these cool methods have their plain-**C** equivalents, it would be great if they did. Thanks nevertheless. – user3078414 Mar 12 '16 at 00:20