4

I'm playing with pyaudio on a mac using a Saffire Pro 40 sound card. Currently I have two inputs plugged in and I'd like to control the levels of the second input channel programmatically. (This works fine using the sound card's mix control software).

I've been going through the pyaudio docs, but haven't found anything glaring on this issue so far. What's the simplest way to essentially do what the mix control software does (control volume per channel) programmatically? (A Python API would be nice, but not essential)

To simplify: it looks like it's possible to manually read the streams from the channels I want to control, scale them using numpy, them write them as output, but I'm hoping there is a method to simply send a normalized value per channel to control it.

So instead of something like this:

stream1 = pyaudioInstance.open( format             = FORMAT,
                                channels           = CHANNELS,
                                rate               = RATE,
                                input              = True,
                                output             = True,
                                input_device_index = 0,
                                frames_per_buffer  = CHUNK
                                )
stream2 = pyaudioInstance.open( format             = FORMAT,
                                channels           = CHANNELS,
                                rate               = RATE,
                                input              = True,
                                input_device_index = 1,
                                frames_per_buffer  = CHUNK
                                )

while processingAudio:
    # manually fetch each channel
    data1In = stream1.read(CHUNK)
    data2In = stream2.read(CHUNK)
    # convert to numpy to easy scale the arrays
    decodeddata1 = numpy.fromstring(data1In, numpy.int16)
    decodeddata2 = numpy.fromstring(data2In, numpy.int16)
    newdata = (decodeddata1 * 0.5 + decodeddata2* 0.1).astype(numpy.int16)
    # finally write the processed data
    stream1.write(result.tostring())

This is a bit misleading but I would need to mix separate channels from the same input device index. However what I'm hoping is something like:

someSoundCardAPI.channels[0].setVolume(0.2)

Having a look at the Channel Maps example feels closer to what I'm after. At the moment I find the host_api_specific part of API a bit confusing and I was hoping someone already has some experience successfully using this.

I am using OSX 10.10

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
George Profenza
  • 50,687
  • 19
  • 144
  • 218
  • 2
    So do you want a way to remote-control your mixer software or do you want to write an application that somehow manipulates input audio and writes the result back to the sound card outputs? You should be a bit more specific. And you should probably mention the OS you are using. – Matthias Sep 16 '15 at 09:27
  • All very good questions, thank you! I've updated the question above. If I could remote-control the mixer software, or tap into it's functionality from code, that would be great! My approach so far is to manipulate audio and write back the result, but I'm hoping there's a way without needing to do that. I am using OSX 10.10 – George Profenza Sep 16 '15 at 13:00

1 Answers1

1

I don't really have any experience with OSX, so I don't know, but normally you can remote-control everything with AppleScript. See, for example, this question. It doesn't say how to control the volume of a single channel separately, though.

Probably you should ask there ...

Regarding the inferior work-around, you can use python-sounddevice to create a little (untested) Python script:

import sounddevice as sd

def callback(indata, outdata, *stuff):
    outdata[:] = indata * [1, 0.5]

with sd.Stream(channels=2, callback=callback):
    input()

This script will run until you press <Return> and it will reduce the volume of the second channel.

Community
  • 1
  • 1
Matthias
  • 4,524
  • 2
  • 31
  • 50