Reputation: 659
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?
Upvotes: 2
Views: 174
Reputation: 2211
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:
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
Upvotes: 2