The Great AVAudioUnitSampler workout

Swift Language

The Great AVAudioUnitSampler workout

Table of Contents

Introduction

Table of Contents

Little by little, AVFoundation audio classes are taking over Core Audio. Unfortunately, the pace is glacial so Core Audio is going to be around for another eon or so.

The AVAudioUnitSampler is the AVFoundation version of the Core Audio kAudioUnitSubType_Sampler AUNode. It is a mono-timbral polyphonic sampler – it plays audio.

With AVFoundation, we create an AVAudioEngine instead of the Core Audio AUGraph. Where the AUGraph had AUNodes attached, the AVAudioEngine has AVAudioNodes attached.

The class hierarchy is:
AVAudioNode -> AVAudioUnit -> AVAudioUnitMIDIInstrument -> AVAudioUnitSampler

The engine already has a mixer node and an output node attached to it out of the box. We simply need to create the sampler, attach it to the engine, and connect the sampler to the mixer.

Since we’re playing audio, the AVAudioSession needs to be configured for that and activated.

Starting the engine is straightforward.

We probably want to ask for notifications when the engine or session changes. Here is how I do that.

Once the engine has been started, you can send MIDI messages to it. For note on/note off messages, perhaps you added actions on a button for touch down and touch up.

MIDI messages are useful, but for actually playing music, use the new AVAudioSequencer.
Its init method connects it to your engine. Then you load a standard MIDI file into the sequencer. The functions start and stop work as expected. But if you’ve already played the sequence, then say start again, you will hear nothing because the current position is no longer at the beginning of the sequence. Simply reset it to 0.

Sampler from SoundFont

Table of Contents

We need to give the sampler some waveforms to play. We have several options. Let’s start with SoundFonts.

The sampler function loadSoundBankInstrumentAtURL will load a SoundFont.

I use a SoundFont from Musescore. There are many SoundFonts available for download online.

You need to specify a General MIDI patch number or program change number. (See resources.) You also need to specify which bank to use within the SoundFont. I use two Core Audio constants to do this.

Sampler from aupreset

Table of Contents

If you don’t have an aupreset file, ready my blog post on how to create one.

Sampler from sound files

Table of Contents

You can have the sampler load a directory of audio files. If the files are in Core Audio Format (caf), you can embed range metadata in each file. A simpler method is to simply name the files with the root pitch at the end of the basename. So, violinC4.wav would map to C4 or middle c.

Multiple voices

Table of Contents

Currently, the sampler is the only subclass of AVAudioUnitMIDIInstrument. There is no equivalent to the multitimbral kAudioUnitSubType_DLSSynth or kAudioUnitSubType_MIDISynth audio units.

What you can do is attach multiple AVAudioUnitSampler instances to the engine.
Something like this:

But what about using a sequencer with that and have the individual tracks use different timbres?
You’d have to create a custom subclass of AVAudioUnitMIDIInstrument perhaps configured as a kAudioUnitSubType_DLSSynth or kAudioUnitSubType_MIDISynth which are multi-timbral audio units.

What a coincidence! My next blog post is about creating a multi-timbral AVAudioUnitMIDIInstrument using kAudioUnitSubType_MIDISynth.

Or you can just use AVMIDIPlayer which uses a sound font and reads a MIDI file.

Summary

Table of Contents

The AVAudioUnitSampler is useful, but needs improvement – especially when used with AVAudioSequencer.

Resources

Table of Contents

Share These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Facebook
  • Twitter
  • LinkedIn
  • email
  • DZone
  • Slashdot
  • Reddit
  • Google Bookmarks
  • Digg
  • StumbleUpon
  • del.icio.us
This entry was posted in AVFoundation, Swift and tagged , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

7 Comments

  1. Paul Wochnick
    Posted March 25, 2016 at 1:33 am | Permalink

    Looks like xCode 7.3 is breaking the project. “Terminating app due to uncaught exception ‘com.apple.coreaudio.avfaudio’, reason: ‘error -10851′”

    Any ideas what is causing it?

    • Paul Wochnick
      Posted March 25, 2016 at 4:05 pm | Permalink

      Hmmm… on another machine with xCode 7.3 it works fine. I guess you can ignore the message above.

  2. narco
    Posted November 17, 2016 at 7:01 pm | Permalink

    I’m trying to figure out how to adjust the envelopes for an AVAudioUnitSampler, or to be more specific I have made a sampler out of CAFs that are drum hits, and I want each hit to play to the end, no matter how long the midi note is held. Do you have any idea how to achieve this?
    I tried hacky approach of only sending the startNote, and no stopNote but I get loads of clicks and pops as the sample stops by itself about a second in.
    I am actually using an AKMidiSampler, but it is essentially just a wrapper for the AVAudioUnitSampler, as far as I know.

  3. Jacob
    Posted December 24, 2016 at 2:50 pm | Permalink

    Have you had any success attaching multiple samplers to one engine? When I tried it, it only the last one will play using the assigned instrument.

    • Posted January 3, 2017 at 7:46 pm | Permalink

      I narrowed the problem down. The multiple samplers *are* being created and added. The reason I only hear one playing is because I’m loading multiple MIDI files, but multiple tracks are not being created by AVAudioSequencer. Any idea how to force that, or is it simply something we don’t have control over?

      • Gene De Lisa
        Posted January 4, 2017 at 12:20 pm | Permalink

        I can’t tell without looking.
        Email me a link to your repo or zip the code and email it.
        I’ll take a look.

        • Posted January 4, 2017 at 2:20 pm | Permalink

          Here it is. https://github.com/jadar/SwiftMIDI

          The aim is to load all the tracks from the 4 midi files and play them simultaneously, being able to adjust each track’s volume independently. I hope the comments are sufficient. I can provide more information if needed.

Post a Comment

Your email is never published nor shared.

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">