Good morning, collective wisdom!

I have written an iOS 16-channel General MIDI tone generator using an AUGraph, 
and it works great with some DLSs and sound fonts, and sounds terrible with 
others. With some DLSs and sound fonts, I can play a sequence and get 
essentially the same sound as I hear from other iOS apps (e.g. bs-16i) playing 
the same sequence and using the same DLS or sound font; but with DLSs or sound 
fonts, I get a much worse sound quality than from the other app, notes that 
don't sound, etc.--not even close to acceptable. It's particularly surprising 
since the difference in quality exists only for some DLSs and sound fonts--so 
what I'm doing works for some, but is not sufficient for others.

Below is the function newAUGraph(), which creates an AUGraph consisting of 16 
AUSamplers (one for each channel), each with an output to a mixer, which 
combines the 16 channels and routes them to a reverb unit, which then sends the 
sounds to the output unit; the AUGraph and the sixteen AUSamplers are stored in 
the external (global) variables auGraph and auSampler[16].  Presets are 
subsequently loaded into each channel's AUSampler, and notes and other MIDI 
messages are sent via MusicDeviceMIDIEvent().

If anybody has time to slog through this and give me a hint as to what I'm 
missing, I'll be forever grateful.  In any case, thanks for your attention!

All best,
Frank


****************

AUGraph auGraph;
AudioUnit auSampler[16];

#define mustHaveNoError(functionCall) functionCall; if (result != noErr) {NSLog 
(@"error %d", (int)result); return result;}

static OSStatus newAUGraph (void)
        {
        AudioUnit mixerAudioUnit, reverbAudioUnit, outputAudioUnit;
        AUNode samplerNode[16], mixerNode, reverbNode, outputNode;

        AVAudioSession* avAudioSession = [AVAudioSession sharedInstance];
        [avAudioSession setCategory: AVAudioSessionCategoryPlayback error: nil];
        [avAudioSession setPreferredHardwareSampleRate:44100.0 error:nil];
        [avAudioSession setActive:YES error:nil];
        Float64 sampleRate = avAudioSession.currentHardwareSampleRate;

        AudioComponentDescription description;
        description.componentManufacturer = kAudioUnitManufacturer_Apple;
        description.componentFlags = description.componentFlagsMask = 0;

        OSStatus result = mustHaveNoError(NewAUGraph(&auGraph));

        description.componentType = kAudioUnitType_Output;
        description.componentSubType = kAudioUnitSubType_RemoteIO;
        result = mustHaveNoError(AUGraphAddNode (auGraph, &description, 
&outputNode));

        description.componentType = kAudioUnitType_Effect;
        description.componentSubType = kAudioUnitSubType_Reverb2;
        result = mustHaveNoError(AUGraphAddNode (auGraph, &description, 
&reverbNode));

        description.componentType = kAudioUnitType_Mixer;
        description.componentSubType = kAudioUnitSubType_MultiChannelMixer;
        result = mustHaveNoError(AUGraphAddNode (auGraph, &description, 
&mixerNode));

        result = mustHaveNoError(AUGraphConnectNodeInput(auGraph, reverbNode, 
0, outputNode, 0));
        result = mustHaveNoError(AUGraphConnectNodeInput(auGraph, mixerNode, 0, 
reverbNode, 0));

        const UInt32 numberOfChannels = 16;
        for (unsigned int i = 0; i < numberOfChannels; i += 1)
                {
                description.componentType = kAudioUnitType_MusicDevice;
                description.componentSubType = kAudioUnitSubType_Sampler;
                result = mustHaveNoError(AUGraphAddNode (auGraph, &description, 
&samplerNode[i]));
                result = mustHaveNoError(AUGraphConnectNodeInput(auGraph, 
samplerNode[i], 0, mixerNode, i));
                }

        result = mustHaveNoError(AUGraphOpen (auGraph));

        result = mustHaveNoError(AUGraphNodeInfo(auGraph, mixerNode, NULL, 
&mixerAudioUnit));
        result = mustHaveNoError(AUGraphNodeInfo(auGraph, reverbNode, NULL, 
&reverbAudioUnit));
        result = mustHaveNoError(AUGraphNodeInfo(auGraph, outputNode, NULL, 
&outputAudioUnit));

        UInt32 framesPerSlice;
        UInt32 framesPerSlicePropertySize = sizeof(framesPerSlice);
        result = mustHaveNoError(AudioUnitGetProperty(outputAudioUnit, 
kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, 
&framesPerSlice, &framesPerSlicePropertySize));
        assert(framesPerSlicePropertySize == sizeof(framesPerSlice));

        result = mustHaveNoError(AudioUnitInitialize(outputAudioUnit));
        result = mustHaveNoError(AudioUnitSetProperty(outputAudioUnit, 
kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, 
sizeof(sampleRate)));
        result = mustHaveNoError(AudioUnitSetProperty(outputAudioUnit, 
kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, &sampleRate, 
sizeof(sampleRate)));
        result = mustHaveNoError(AudioUnitSetProperty(reverbAudioUnit, 
kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, 
sizeof(sampleRate)));
        result = mustHaveNoError(AudioUnitSetProperty(reverbAudioUnit, 
kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, &sampleRate, 
sizeof(sampleRate)));
        result = mustHaveNoError(AudioUnitSetProperty(reverbAudioUnit, 
kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, 
&framesPerSlice, sizeof(framesPerSlice)));
        result = mustHaveNoError(AudioUnitSetProperty(mixerAudioUnit, 
kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, 
sizeof(sampleRate)));
        result = mustHaveNoError(AudioUnitSetProperty(mixerAudioUnit, 
kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, 
&framesPerSlice, sizeof(framesPerSlice)));

        result = mustHaveNoError(AudioUnitSetProperty(mixerAudioUnit, 
kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &numberOfChannels, 
sizeof(numberOfChannels)));

        result = mustHaveNoError(AudioUnitSetParameter(reverbAudioUnit, 
kReverb2Param_DryWetMix, kAudioUnitScope_Global, 0, 20, 0));
        result = mustHaveNoError(AudioUnitSetParameter(reverbAudioUnit, 
kReverb2Param_DecayTimeAt0Hz, kAudioUnitScope_Global, 0, 3, 0));
        result = mustHaveNoError(AudioUnitSetParameter(reverbAudioUnit, 
kReverb2Param_DecayTimeAtNyquist, kAudioUnitScope_Global, 0, 1, 0));

        for (unsigned int i = 0; i < numberOfChannels; i += 1)
                {
                result = mustHaveNoError(AUGraphNodeInfo(auGraph, 
samplerNode[i], NULL, &auSampler[i]));
                result = mustHaveNoError(AudioUnitSetProperty(auSampler[i], 
kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, 
sizeof(sampleRate)));
                result = mustHaveNoError(AudioUnitSetProperty(auSampler[i], 
kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, 
&framesPerSlice, sizeof(framesPerSlice)));
                result = mustHaveNoError(AudioUnitSetProperty(mixerAudioUnit, 
kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, i, &sampleRate, 
sizeof(sampleRate)));
                result = mustHaveNoError(AudioUnitSetProperty(mixerAudioUnit, 
kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, i, 
&framesPerSlice, sizeof(framesPerSlice)));
                result = mustHaveNoError(loadOnBoardSynthPatch(0, i));
                result = mustHaveNoError(AudioUnitSetParameter(mixerAudioUnit, 
kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, i, 1, 0));
                }

        result = mustHaveNoError(AUGraphInitialize(auGraph));
        result = mustHaveNoError(AUGraphStart(auGraph));

        CAShow(auGraph);
        return result;
        }


****************

Frank Weinstock
Professor Emeritus of Piano
College-Conservatory of Music
University of Cincinnati
[email protected]





 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list      ([email protected])
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/coreaudio-api/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to