Support selecting separate input and output devices in portaudio backend
authorTim Mayberry <mojofunk@gmail.com>
Sat, 9 May 2015 01:42:46 +0000 (11:42 +1000)
committerTim Mayberry <mojofunk@gmail.com>
Thu, 30 Jul 2015 23:59:54 +0000 (09:59 +1000)
libs/backends/portaudio/portaudio_backend.cc
libs/backends/portaudio/portaudio_backend.h
libs/backends/portaudio/portaudio_io.cc
libs/backends/portaudio/portaudio_io.h

index 1e3722ddcda34528ae49e42be47f3dd9b84b2db1..71986cd3764bf505c5a5b8d0c002e718301c70c4 100644 (file)
@@ -41,7 +41,8 @@ using namespace ARDOUR;
 static std::string s_instance_name;
 size_t PortAudioBackend::_max_buffer_size = 8192;
 std::vector<std::string> PortAudioBackend::_midi_options;
-std::vector<AudioBackend::DeviceStatus> PortAudioBackend::_audio_device_status;
+std::vector<AudioBackend::DeviceStatus> PortAudioBackend::_input_audio_device_status;
+std::vector<AudioBackend::DeviceStatus> PortAudioBackend::_output_audio_device_status;
 
 PortAudioBackend::PortAudioBackend (AudioEngine& e, AudioBackendInfo& info)
        : AudioBackend (e, info)
@@ -51,7 +52,8 @@ PortAudioBackend::PortAudioBackend (AudioEngine& e, AudioBackendInfo& info)
        , _freewheel (false)
        , _measure_latency (false)
        , _last_process_start (0)
-       , _audio_device("")
+       , _input_audio_device("")
+       , _output_audio_device("")
        , _midi_driver_option(_("None"))
        , _samplerate (48000)
        , _samples_per_period (1024)
@@ -116,26 +118,53 @@ PortAudioBackend::set_driver (const std::string& name)
        return 0;
 }
 
+bool
+PortAudioBackend::use_separate_input_and_output_devices () const
+{
+       return true;
+}
+
 std::vector<AudioBackend::DeviceStatus>
 PortAudioBackend::enumerate_devices () const
+{
+       return std::vector<AudioBackend::DeviceStatus>();
+}
+
+std::vector<AudioBackend::DeviceStatus>
+PortAudioBackend::enumerate_input_devices () const
 {
        _pcmio->discover();
-       _audio_device_status.clear();
-       std::map<int, std::string> devices;
-       _pcmio->device_list(devices);
+       _input_audio_device_status.clear();
+       std::map<int, std::string> input_devices;
+       _pcmio->input_device_list(input_devices);
 
-       for (std::map<int, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
-               if (_audio_device == "") _audio_device = i->second;
-               _audio_device_status.push_back (DeviceStatus (i->second, true));
+       for (std::map<int, std::string>::const_iterator i = input_devices.begin (); i != input_devices.end(); ++i) {
+               if (_input_audio_device == "") _input_audio_device = i->second;
+               _input_audio_device_status.push_back (DeviceStatus (i->second, true));
+       }
+       return _input_audio_device_status;
+}
+
+std::vector<AudioBackend::DeviceStatus>
+PortAudioBackend::enumerate_output_devices () const
+{
+       _pcmio->discover();
+       _output_audio_device_status.clear();
+       std::map<int, std::string> output_devices;
+       _pcmio->output_device_list(output_devices);
+
+       for (std::map<int, std::string>::const_iterator i = output_devices.begin (); i != output_devices.end(); ++i) {
+               if (_output_audio_device == "") _output_audio_device = i->second;
+               _output_audio_device_status.push_back (DeviceStatus (i->second, true));
        }
-       return _audio_device_status;
+       return _output_audio_device_status;
 }
 
 std::vector<float>
 PortAudioBackend::available_sample_rates (const std::string&) const
 {
        std::vector<float> sr;
-       _pcmio->available_sample_rates(name_to_id(_audio_device), sr);
+       _pcmio->available_sample_rates(name_to_id(_input_audio_device), sr);
        return sr;
 }
 
@@ -143,7 +172,7 @@ std::vector<uint32_t>
 PortAudioBackend::available_buffer_sizes (const std::string&) const
 {
        std::vector<uint32_t> bs;
-       _pcmio->available_buffer_sizes(name_to_id(_audio_device), bs);
+       _pcmio->available_buffer_sizes(name_to_id(_input_audio_device), bs);
        return bs;
 }
 
@@ -174,7 +203,20 @@ PortAudioBackend::can_change_buffer_size_when_running () const
 int
 PortAudioBackend::set_device_name (const std::string& d)
 {
-       _audio_device = d;
+       return 0;
+}
+
+int
+PortAudioBackend::set_input_device_name (const std::string& d)
+{
+       _input_audio_device = d;
+       return 0;
+}
+
+int
+PortAudioBackend::set_output_device_name (const std::string& d)
+{
+       _output_audio_device = d;
        return 0;
 }
 
@@ -238,7 +280,19 @@ PortAudioBackend::set_systemic_output_latency (uint32_t sl)
 std::string
 PortAudioBackend::device_name () const
 {
-       return _audio_device;
+       return "Unused";
+}
+
+std::string
+PortAudioBackend::input_device_name () const
+{
+       return _input_audio_device;
+}
+
+std::string
+PortAudioBackend::output_device_name () const
+{
+       return _output_audio_device;
 }
 
 float
@@ -349,7 +403,7 @@ PortAudioBackend::_start (bool for_latency_measurement)
        _freewheel = false;
        _last_process_start = 0;
 
-       _pcmio->pcm_setup (name_to_id(_audio_device), name_to_id(_audio_device), _samplerate, _samples_per_period);
+       _pcmio->pcm_setup (name_to_id(_input_audio_device), name_to_id(_output_audio_device), _samplerate, _samples_per_period);
 
        switch (_pcmio->state ()) {
                case 0: /* OK */ break;
@@ -515,7 +569,8 @@ int
 PortAudioBackend::name_to_id(std::string device_name) const {
        uint32_t device_id = UINT32_MAX;
        std::map<int, std::string> devices;
-       _pcmio->device_list(devices);
+       _pcmio->input_device_list(devices);
+       _pcmio->output_device_list(devices);
 
        for (std::map<int, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
                if (i->second == device_name) {
index 1f802c7a5f2f671357bd3abd5800340a99733884..d3def25fb1fec6e7943f5263f4639c852476af83 100644 (file)
@@ -164,7 +164,11 @@ class PortAudioBackend : public AudioBackend {
                std::vector<std::string> enumerate_drivers () const;
                int set_driver (const std::string&);
 
+               bool use_separate_input_and_output_devices () const;
                std::vector<DeviceStatus> enumerate_devices () const;
+               std::vector<DeviceStatus> enumerate_input_devices () const;
+               std::vector<DeviceStatus> enumerate_output_devices () const;
+
                std::vector<float> available_sample_rates (const std::string& device) const;
                std::vector<uint32_t> available_buffer_sizes (const std::string& device) const;
                uint32_t available_input_channel_count (const std::string& device) const;
@@ -174,6 +178,8 @@ class PortAudioBackend : public AudioBackend {
                bool can_change_buffer_size_when_running () const;
 
                int set_device_name (const std::string&);
+               int set_input_device_name (const std::string&);
+               int set_output_device_name (const std::string&);
                int set_sample_rate (float);
                int set_buffer_size (uint32_t);
                int set_interleaved (bool yn);
@@ -188,6 +194,8 @@ class PortAudioBackend : public AudioBackend {
 
                /* Retrieving parameters */
                std::string  device_name () const;
+               std::string  input_device_name () const;
+               std::string  output_device_name () const;
                float        sample_rate () const;
                uint32_t     buffer_size () const;
                bool         interleaved () const;
@@ -314,10 +322,12 @@ class PortAudioBackend : public AudioBackend {
                uint64_t _last_process_start;
 
                static std::vector<std::string> _midi_options;
-               static std::vector<AudioBackend::DeviceStatus> _audio_device_status;
+               static std::vector<AudioBackend::DeviceStatus> _input_audio_device_status;
+               static std::vector<AudioBackend::DeviceStatus> _output_audio_device_status;
                static std::vector<AudioBackend::DeviceStatus> _midi_device_status;
 
-               mutable std::string _audio_device;
+               mutable std::string _input_audio_device;
+               mutable std::string _output_audio_device;
                std::string _midi_driver_option;
 
                /* audio settings */
index 77ea0536fb830c454c4882641b9c57074e20937d..a7c4516b53f9a4d0d29b9fd5f6648e8b76d9a847 100644 (file)
@@ -51,10 +51,7 @@ PortAudioIO::~PortAudioIO ()
                Pa_Terminate();
        }
 
-       for (std::map<int, paDevice*>::const_iterator i = _devices.begin (); i != _devices.end(); ++i) {
-               delete i->second;
-       }
-       _devices.clear();
+       clear_device_lists ();
 
        free (_input_buffer); _input_buffer = NULL;
        free (_output_buffer); _output_buffer = NULL;
@@ -126,10 +123,22 @@ PortAudioIO::available_buffer_sizes(int device_id, std::vector<uint32_t>& buffer
 }
 
 void
-PortAudioIO::device_list (std::map<int, std::string> &devices) const {
-       devices.clear();
-       for (std::map<int, paDevice*>::const_iterator i = _devices.begin (); i != _devices.end(); ++i) {
-               devices.insert (std::pair<int, std::string> (i->first, Glib::locale_to_utf8(i->second->name)));
+PortAudioIO::input_device_list(std::map<int, std::string> &devices) const
+{
+       for (std::map<int, paDevice*>::const_iterator i = _input_devices.begin ();
+            i != _input_devices.end ();
+            ++i) {
+               devices.insert (std::pair<int, std::string>(i->first, Glib::locale_to_utf8(i->second->name)));
+       }
+}
+
+void
+PortAudioIO::output_device_list(std::map<int, std::string> &devices) const
+{
+       for (std::map<int, paDevice*>::const_iterator i = _output_devices.begin ();
+            i != _output_devices.end ();
+            ++i) {
+               devices.insert (std::pair<int, std::string>(i->first, Glib::locale_to_utf8(i->second->name)));
        }
 }
 
@@ -211,16 +220,21 @@ PortAudioIO::get_default_output_device ()
 }
 
 void
-PortAudioIO::clear_device_list ()
+PortAudioIO::clear_device_lists ()
 {
-       for (std::map<int, paDevice*>::const_iterator i = _devices.begin (); i != _devices.end(); ++i) {
+       for (std::map<int, paDevice*>::const_iterator i = _input_devices.begin (); i != _input_devices.end(); ++i) {
+               delete i->second;
+       }
+       _input_devices.clear();
+
+       for (std::map<int, paDevice*>::const_iterator i = _output_devices.begin (); i != _output_devices.end(); ++i) {
                delete i->second;
        }
-       _devices.clear();
+       _output_devices.clear();
 }
 
 void
-PortAudioIO::add_default_device ()
+PortAudioIO::add_default_devices ()
 {
        const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
        if (info == NULL) return;
@@ -228,7 +242,12 @@ PortAudioIO::add_default_device ()
        const PaDeviceInfo* nfo_i = Pa_GetDeviceInfo(get_default_input_device());
        const PaDeviceInfo* nfo_o = Pa_GetDeviceInfo(get_default_output_device());
        if (nfo_i && nfo_o) {
-               _devices.insert (std::pair<int, paDevice*> (-1,
+               _input_devices.insert (std::pair<int, paDevice*> (-1,
+                                       new paDevice("Default",
+                                               nfo_i->maxInputChannels,
+                                               nfo_o->maxOutputChannels
+                                               )));
+               _output_devices.insert (std::pair<int, paDevice*> (-1,
                                        new paDevice("Default",
                                                nfo_i->maxInputChannels,
                                                nfo_o->maxOutputChannels
@@ -267,11 +286,20 @@ PortAudioIO::add_devices ()
                        continue;
                }
 
-               _devices.insert (std::pair<int, paDevice*> (i, new paDevice(
-                                               nfo->name,
-                                               nfo->maxInputChannels,
-                                               nfo->maxOutputChannels
-                                               )));
+               if (nfo->maxInputChannels > 0) {
+                       _input_devices.insert (std::pair<int, paDevice*> (i, new paDevice(
+                                                       nfo->name,
+                                                       nfo->maxInputChannels,
+                                                       nfo->maxOutputChannels
+                                                       )));
+               }
+               if (nfo->maxOutputChannels > 0) {
+                       _output_devices.insert (std::pair<int, paDevice*> (i, new paDevice(
+                                                       nfo->name,
+                                                       nfo->maxInputChannels,
+                                                       nfo->maxOutputChannels
+                                                       )));
+               }
        }
 }
 
@@ -280,8 +308,8 @@ PortAudioIO::discover()
 {
        if (!initialize_pa()) return;
 
-       clear_device_list ();
-       add_default_device ();
+       clear_device_lists ();
+       add_default_devices ();
        add_devices ();
 }
 
index fccda4f05e13f4e9d884ae035a554b5c1b8edc92..2f90a1d1a6cfec6702571ce8f1d557ef45e37b5b 100644 (file)
@@ -47,7 +47,8 @@ public:
        PaDeviceIndex get_default_output_device ();
 
        void     discover();
-       void     device_list (std::map<int, std::string> &devices) const;
+       void     input_device_list (std::map<int, std::string> &devices) const;
+       void     output_device_list (std::map<int, std::string> &devices) const;
 
        int      available_sample_rates (int device_id, std::vector<float>& sampleRates);
        int      available_buffer_sizes (int device_id, std::vector<uint32_t>& sampleRates);
@@ -77,8 +78,8 @@ public:
 
 private: // Methods
 
-       void clear_device_list ();
-       void add_default_device ();
+       void clear_device_lists ();
+       void add_default_devices ();
        void add_devices ();
 
 private: // Data
@@ -109,7 +110,8 @@ private: // Data
                {}
        };
 
-       std::map<int, paDevice *> _devices;
+       std::map<int, paDevice *> _input_devices;
+       std::map<int, paDevice *> _output_devices;
 
        PaHostApiIndex _host_api_index;