+ ofSoundDevice

This closes #2785

It adds a new struct `ofSoundDevice`, which represents a sound device with a numeric ID, name, number of i/o channels and vector of sample rates, modeled after the `RtAudio::DeviceInfo` struct.

This PR changes `ofSoundStreamListDevices()` into a function which returns a `vector<ofSoundDevice>` and now *optionally* logs to the console. It also adds a function `ofSoundStreamGetMatchingDevices(...)` which lets you find a device by partial name, and optionally with an i/o channel count. You can also set an ofSoundStream's device with an ofSoundDevice directly (instead of just via ID). Does this fit your use-case @kylemcdonald ?

On my OSX laptop I get the following:

**ofSoundStreamGetMatchingDevices("Soundflower")**
```
(std::vector<ofSoundDevice, std::allocator<ofSoundDevice> >) $0 = size=2 {
  [0] = {
    name = "ma++ ingalls for Cycling '74: Soundflower (2ch)"
    deviceID = 2
    inputChannels = 2
    outputChannels = 2
    isDefaultInput = false
    isDefaultOutput = false
    sampleRates = size=6 {
      [0] = 44100
      [1] = 48000
      [2] = 88200
      [3] = 96000
      [4] = 176400
      [5] = 192000
    }
  }
  [1] = {
    name = "ma++ ingalls for Cycling '74: Soundflower (64ch)"
    deviceID = 3
    inputChannels = 64
    outputChannels = 64
    isDefaultInput = false
    isDefaultOutput = false
    sampleRates = size=6 {
      [0] = 44100
      [1] = 48000
      [2] = 88200
      [3] = 96000
      [4] = 176400
      [5] = 192000
    }
  }
}
```

**ofSoundStreamGetMatchingDevices("Apple", 0, 2)**
```
(std::vector<ofSoundDevice, std::allocator<ofSoundDevice> >) $0 = size=1 {
  [0] = {
    name = "Apple Inc.: Built-in Output"
    deviceID = 1
    inputChannels = 0
    outputChannels = 2
    isDefaultInput = false
    isDefaultOutput = true
    sampleRates = size=4 {
      [0] = 44100
      [1] = 48000
      [2] = 88200
      [3] = 96000
    }
  }
}
```

Tested on OSX, iOS and Windows, but the change touches all platforms due to the function signature change. The Android and Emscripten changes are a shot in the dark, pinging @arturoc