Line data Source code
1 : // =============================================================================
2 : // PortAudio backend — native desktop (Linux, macOS, Windows)
3 : //
4 : // Provides the AudioBackendState factory/destructor, helper functions,
5 : // auto-device detection, and the audio callback.
6 : // =============================================================================
7 :
8 : #include "audio/engine/audio_engine.h"
9 : #include "audio/backend/audio_backend.h"
10 : #include "audio/backend/audio_backend_portaudio_helpers.h"
11 : #include "audio/backend/audio_backend_portaudio_internal.h"
12 : #include <portaudio.h>
13 : #ifdef _WIN32
14 : #include <pa_win_wasapi.h>
15 : #endif
16 : #include <cstring>
17 : #include <iostream>
18 : #include <cctype>
19 : #include <algorithm>
20 : #include <vector>
21 :
22 : namespace Amplitron {
23 :
24 : // AudioBackendState is defined in audio_backend_portaudio_internal.h
25 :
26 583 : AudioBackendState* create_audio_backend() {
27 583 : return new AudioBackendState();
28 : }
29 :
30 583 : void destroy_audio_backend(AudioBackendState* state) {
31 583 : delete state;
32 583 : }
33 :
34 : // -----------------------------------------------------------------------------
35 : // Helper functions — promoted to non-static for use across TUs
36 : // -----------------------------------------------------------------------------
37 :
38 1660 : bool is_usb_device_name(const std::string& name) {
39 1660 : std::string lower = name;
40 1660 : std::transform(lower.begin(), lower.end(), lower.begin(),
41 37954 : [](unsigned char c) { return std::tolower(c); });
42 :
43 16 : static const char* usb_keywords[] = {
44 : "usb", "guitar", "guitar link", "irig", "scarlett",
45 : "behringer", "focusrite", "presonus", "steinberg",
46 : "audio interface", "line 6", "rocksmith", "umc",
47 : "um2", "uphoria", "podcast", "xenyx"
48 : };
49 :
50 29684 : for (const auto* keyword : usb_keywords) {
51 28036 : if (lower.find(keyword) != std::string::npos) {
52 6 : return true;
53 : }
54 : }
55 1638 : return false;
56 1660 : }
57 :
58 1356 : int get_host_api_priority(int host_api_type) {
59 1356 : auto type = static_cast<PaHostApiTypeId>(host_api_type);
60 : #if defined(__linux__)
61 : switch (type) {
62 : case paJACK: return 100;
63 : case paALSA: return 70;
64 : default: return 10;
65 : }
66 : #elif defined(_WIN32)
67 1080 : switch (type) {
68 : case paASIO: return 100;
69 : case paWASAPI: return 90;
70 : case paDirectSound: return 40;
71 : case paMME: return 10;
72 : default: return 20;
73 : }
74 : #elif defined(__APPLE__)
75 276 : switch (type) {
76 272 : case paCoreAudio: return 100;
77 4 : default: return 30;
78 : }
79 : #else
80 : (void)type;
81 : return 30;
82 : #endif
83 276 : }
84 :
85 820 : bool is_projector_or_hdmi(const std::string& name) {
86 820 : std::string lower = name;
87 820 : std::transform(lower.begin(), lower.end(), lower.begin(),
88 18712 : [](unsigned char c) { return std::tolower(c); });
89 820 : return lower.find("epson") != std::string::npos
90 819 : || lower.find("projector") != std::string::npos
91 818 : || lower.find("hdmi") != std::string::npos
92 828 : || lower.find("displayport") != std::string::npos;
93 820 : }
94 :
95 2 : bool devices_share_host_api(int input_dev, int output_dev) {
96 2 : const PaDeviceInfo* in_info = Pa_GetDeviceInfo(input_dev);
97 2 : const PaDeviceInfo* out_info = Pa_GetDeviceInfo(output_dev);
98 2 : if (!in_info || !out_info) return false;
99 0 : return in_info->hostApi == out_info->hostApi;
100 1 : }
101 :
102 : /** @brief Auto-detect the best input/output device pair. */
103 :
104 : } // namespace Amplitron
|