1 Reply
      Latest reply on Nov 9, 2019 5:25 AM by samp17
      samp17 Level 1 Level 1 (0 points)

        I have an audio interface which does multiple channels, of which I want to use just the first channel. This comes into my device at the hardware’s preferred sample rate.


        What I would like to achieve is to downsample the incoming signal to my apps native format and to record the first channel. To do this, I have the engine.inputNode coming into an AVAudioMixer (called formatMixer) at the inputNode.outputFormat. I then connect this formatMixer to an AVAudioSinkNode to record the data.


        I have two issues here. Looking at the what’s new in audioAPI video from July, Using a sinkNode I cannot specify the format. It will take the format of the formatMixer outputNode. So how do I specify this, as usually I would do this at the connection call?


        My second question is: whilst doing the format conversion at the formatMixer stage, is there a way to map the channel output? I do not want to mix down as the documentation suggests, but instead make sure only the first channel of the mixers input bus is sent to the mixers output.

        • Re: How to extract one channel of an input stream
          samp17 Level 1 Level 1 (0 points)

          I have had a play with this, and have tried inserting a second intermediate AVAudioMixerNode.  My thoery that when I connect the two mixers, I can select the format conversion then, and can then connect the output of the intermediateMixer to AVAudioSinkNode.


          When I try thisI get peculiar results:


          let outputFormat = engine.outputNode.outputFormat(forBus: 0)
          let inputFormat = engine.inputNode.outputFormat(forBus: 0)
          let requiredFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32,
                  sampleRate: Double(sampleRate),
                  channels: 1,
                  interleaved: false) 
          let formatMixer = AVAudioMixerNode()
          let intermediateMixer = AVAudioMixerNode()
          engine.connect(input, to: formatMixer, format: inputFormat)
          engine.connect(formatMixer, to: intermediateMixer, format: requiredFormat)
          engine.connect(intermediateMixer, to: MicSinkNode, format: nil)


          If I print to console the various formats along the way, I get:

          Output Format is <AVAudioFormat 0x600002143930:  4 ch,  48000 Hz, Float32, non-inter>

          InputNode Format is <AVAudioFormat 0x60000211ae90:  4 ch,  48000 Hz, Float32, non-inter>

          Required Format for input is: Optional(<AVAudioFormat 0x60000213ed00:  1 ch,  48000 Hz, Float32>)

          FormatMixer Format is <AVAudioFormat 0x6000021496d0:  1 ch,  48000 Hz, Float32>

          Intermediate Format is <AVAudioFormat 0x600002149770:  1 ch,  48000 Hz, Float32>

          MicSinkNode Format is <AVAudioFormat 0x600002149810:  2 ch,  44100 Hz, Float32, non-inter>


          Where does MicSinkNode get this format from?  If I compare my original signal to the result from MicSinkNode, the result is the same length with no glitches. Despite being a different sampleRate at. this stage. 

          What is interesting is that if I change the line to:

          engine.connect(intermediateMixer, to: MicSinkNode, format: requiredFormat) so that all of the formats match and the MicSinkNode Format is the same as requiredFormat, comparing the WAVs, the output of MicSinkNode is shorter than the original signal (as if a 44.1k has been read directly into a 48k stream). And the regular clock slip glitches are apparent in the audio. 


          So how do I correctly get a input signal int a single 48k buffer that I can read into an array?