2

I am creating a toy synth project for my iphone to where i can drag my finger around and frequency and volume changes based on x & y coordinates. It works beautifully, sounds great and the color even changes based on the tone and pitch of the sound. Yahoo. But I am now trying to add effects to this sound and I have reached some sort of confusion.

Currently, I am not using AUGraph. I am simpler calling upon the remoteIO unit and assigning it a render callback function where I am feeding it a continuous stream of sample values to form a sin wave. and i hear a clear 440.00hz sin wave play out of my iphone6+ and it is very nice.

But if I want to add reverb as a second component here I'm not sure what to do because isn't the output unit the "last" unit before the audio hardware? How can I setup another audio unit called reverbUnit and connect it to my current remoteiO ?? It doesn't even make sense. One needs 3 units here. The first to generate the sin wave, the second to add the reverb filter, and than the third to push to hardware.

What am I missing? Can I tack on reverb just by using the remoteio by it self?

1 Answers1

2

Yes the best way would be to use a graph.

The RemoteIO input is actually a pull architecture (not a push). The render callback is where you provide your input samples (sin wav data). It calls back every X milliseconds and asks that you copy samples into the. So it pulls your data. You are NOT constructing a buffer and "pushing" into the audio system on your terms. Rather, you copy it in as it requests more data (pull).

So if you want to add more audio units, you need to connect them with a graph. The remoteIO unit would be the last one in the chain. A reverb unit would be added before the remote IO. So it would look like this:

[ Reverb ] - [ RemoteIO (output element) ]

Your reverb output goes to the remote IO input. When the remote IO needs samples, it PULLs from the reverb unit. The graph connection takes care of the remote IO passing the pull on to the reverb unit. This would then automatically trigger the callback for your reverb unit. So you need to write your samples now in the reverb input callback.

Here's what happens:

  1. Hardware says gimme some samples.
  2. It invokes your remote IO render callback.
  3. Your remote IO invokes your reverb input callback (via the graph connection)
  4. You provide samples to the reverb input callback.

The graph makes it nice because you can just "connect" things together and add/remove things in the signal chain. It just keeps pulling through the chain and you eventually provide data to the first unit in the chain.

If you never made a graph before, be sure to absolute examine the return code of EVERY SINGLE STEP.

All of these functions have error code returns an OSStatus

AUGraphOpen, AUGraphNodeInfo, AUGraphConnectNodeInput, AUGraphInitialize, AudioUnitSetProperty, AUGraphStart,  etc.

After you initialize your graph, you can display it to the console using CAShow(_audioGraph) and get some output like:

Member Nodes:
node 1: 'auou' 'rioc' 'appl', instance 0x7a141060 O I
node 2: 'aumx' 'mcmx' 'appl', instance 0x7a021810 O I
node 3: 'aufx' 'rvb2' 'appl', instance 0x7a0a84a0 O I
node 4: 'aufc' 'splt' 'appl', instance 0x7a025b90 O I
node 5: 'aufc' 'conv' 'appl', instance 0x7a24b9e0 O I
node 6: 'augn' 'afpl' 'appl', instance 0x7a22a220 O  
Connections:
node   2 bus   0 => node   3 bus   0  [ 2 ch,  44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node   3 bus   0 => node   1 bus   0  [ 2 ch,  44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node   4 bus   0 => node   2 bus   0  [ 2 ch,  44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node   5 bus   0 => node   4 bus   0  [ 2 ch,  44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
Input Callbacks:
{0x6ccf0, 0x7a13da00} => node   5 bus   0  [2 ch, 44100 Hz]
CurrentState:
mLastUpdateError=0, eventsToProcess=F, isInitialized=T, isRunning=F
jaybers
  • 1,991
  • 13
  • 18
  • 1
    Thank you. Actually after an hour of looking at my graph construction function I realized that I didn't need a third unit to provide a data stream to the reverb unit but rather two units and a callback function for the reverb. So I guess the graph not only initializes the audio units but when you make connections it creates and assigns the callback procedures behind the scenes? – Alexander Bollbach Jan 02 '16 at 08:00
  • Actually the "nodes" are what are connected. I probably could have been a little better with my wording. AUGraphConnectNodeInput is what connects two nodes together. Yes - once you connect all your nodes properly, AUGraphInitialize will initialize the units. – jaybers Jan 02 '16 at 08:15
  • Isn't that just semantics? The nodes are connected, the audio units are connected. The end results is one unit pulls data from the one that is before it and so on. – Alexander Bollbach Jan 02 '16 at 09:22