HulaLoop
Simple cross-platform audio loopback and recording.
CLICommon.h
1 #ifndef HULA_CLI_COMMON_H
2 #define HULA_CLI_COMMON_H
3 
4 // Convert numeric defines to strings
5 // https://stackoverflow.com/questions/5459868/concatenate-int-to-string-using-c-preprocessor
6 #define STR_HELPER(x) #x
7 #define STR(x) STR_HELPER(x)
8 
9 #include <iomanip>
10 #include <iostream>
11 #include <string>
12 #include <vector>
13 
14 #include <hlaudio/hlaudio.h>
15 #include <hlcontrol/hlcontrol.h>
16 
17 #include <QCoreApplication>
18 #include <QTextStream>
19 
20 #include <HulaVersion.h>
21 
22 using namespace hula;
23 
24 #define HL_CLI_NAME "hulaloop-cli"
25 #define HL_CLI_ASCII_HEADER "\n" \
26  " _ _ _ _\n" \
27  " | | | | | | | |\n" \
28  " | |__| |_ _| | __ _| | ___ ___ _ __\n" \
29  " | __ | | | | |/ _` | | / _ \\ / _ \\| '_ \\\n" \
30  " | | | | |_| | | (_| | |___| (_) | (_) | |_) |\n" \
31  " |_| |_|\\__,_|_|\\__,_|______\\___/ \\___/| .__/\n" \
32  " | |\n" \
33  " |_|\n" \
34  "----------------------------------------------------\n\n" \
35 
36 
39 #define QCOL(stream, width, text) \
40  stream.setFieldWidth(width); \
41  stream << text; \
42  stream.setFieldWidth(0);
43 
47 namespace hula
48 {
49  class CLI {
50  Q_DECLARE_TR_FUNCTIONS(CLI)
51  };
52 
56  typedef struct HulaImmediateArgs
57  {
61  bool startRecord = false;
62 
66  bool exit = false;
67 
74  std::string delay = "0";
75 
85  std::string duration = STR(HL_INFINITE_RECORD);
86 
93  std::string outputFilePath;
94 
101  std::string inputDevice;
102 
109  std::string outputDevice;
111 
117  inline void printDeviceList(Transport *t)
118  {
119  // Strip one padding char for the extra space
120  int colW = 32 - 1;
121 
122  QTextStream cout(stdout);
123  cout.setAutoDetectUnicode(true);
124  cout.setRealNumberNotation(QTextStream::FixedNotation);
125  cout.setRealNumberPrecision(2);
126  cout.setPadChar('.');
127  cout.setFieldAlignment(QTextStream::AlignLeft);
128 
130 
131  std::vector<Device *> devices;
132  if (settings->getShowRecordDevices())
133  {
134  devices = t->getController()->getDevices((DeviceType)(PLAYBACK | LOOPBACK | RECORD));
135  }
136  else
137  {
138  devices = t->getController()->getDevices((DeviceType)(PLAYBACK | LOOPBACK));
139  }
140 
141  printf("\n");
142  for (size_t i = 0; i < devices.size(); i++)
143  {
144  QCOL(cout, colW, CLI::tr("Device #%1").arg(i).append(" "));
145  cout << " " << devices[i]->getName().c_str() << endl;
146 
147  QCOL(cout, colW, CLI::tr("Record", "device capability").append(" "));
148  cout << " " << ((devices[i]->getType() & DeviceType::RECORD) ? CLI::tr("Yes") : CLI::tr("No")) << endl;
149 
150  QCOL(cout, colW, CLI::tr("Loopback", "device capability").append(" "));
151  cout << " " << ((devices[i]->getType() & DeviceType::LOOPBACK) ? CLI::tr("Yes") : CLI::tr("No")) << endl;
152 
153  QCOL(cout, colW, CLI::tr("Output", "device capability").append(" "));
154  cout << " " << ((devices[i]->getType() & DeviceType::PLAYBACK) ? CLI::tr("Yes") : CLI::tr("No")) << endl;
155 
156  cout << endl;
157  }
158 
159  Device::deleteDevices(devices);
160  }
161 
175  inline Device *findDevice(Transport *t, const std::string &name, DeviceType type)
176  {
177  Device *device = nullptr;
178  std::vector<Device *> devices;
179 
180  // TODO: Change this when proper device indexing is possible
181  // devices = t->getController()->getDevices(type);
182  devices = t->getController()->getDevices((DeviceType)(DeviceType::LOOPBACK | DeviceType::RECORD | DeviceType::PLAYBACK));
183 
184  // Check if we got a numeric id
185  // Since we all do this differently,
186  // we'll just use the relative ordering to pick
187  // ids
188  int id = -1;
189  try
190  {
191  id = std::stoi(name, nullptr);
192  }
193  catch (std::invalid_argument &e)
194  {
195  // Wasn't an id
196  (void)e;
197  }
198 
199  for (size_t i = 0; i < devices.size(); i++)
200  {
201  // Check id and name
202  if (i == id || devices[i]->getName() == name)
203  {
204  device = devices[i];
205  break;
206  }
207  }
208 
209  // Make a copy so that we can delete all
210  if (device != nullptr)
211  {
212  device = new Device(*device);
213  }
214 
215  Device::deleteDevices(devices);
216 
217  if (device == nullptr)
218  {
219  //: The argument in this text is the name or id of the device that the user searched for
220  fprintf(stderr, "\n%s\n", qPrintable(CLI::tr("Could not find device matching: %1").arg(name.c_str())));
221  }
222 
223  return device;
224  }
225 
229  inline void printSettings(const HulaImmediateArgs &args)
230  {
231  int colW = 32;
232 
233  QTextStream cout(stdout);
234  cout.setAutoDetectUnicode(true);
235  cout.setRealNumberNotation(QTextStream::FixedNotation);
236  cout.setRealNumberPrecision(2);
237  cout.setFieldAlignment(QTextStream::AlignLeft);
238 
240 
241  cout << endl;
242 
243  QCOL(cout, colW, CLI::tr("Output file:", "setting"));
244  cout << QString::fromStdString(args.outputFilePath) << endl;
245 
246  // Using SI typeset for the units. Shouldn't change with localization.
247  // https://english.stackexchange.com/questions/2794/punctuation-with-units
248  QCOL(cout, colW, CLI::tr("Delay:"));
249  cout << stod(args.delay) << " " << CLI::tr("s", "abbreviation for seconds") << endl;
250 
251  QCOL(cout, colW, CLI::tr("Duration:"));
252  cout << stod(args.duration) << " " << CLI::tr("s", "abbreviation for seconds") << endl;
253 
254  QCOL(cout, colW, CLI::tr("Sample rate:"));
255  cout << settings->getSampleRate() << " " << CLI::tr("Hz", "unit") << endl;
256 
257  // TODO: Change this once MP3 gets in here
258  QCOL(cout, colW, CLI::tr("Encoding:"));
259  cout << "WAV" << endl;
260 
261  QCOL(cout, colW, CLI::tr("Input device:"));
262  cout << QString::fromStdString(args.inputDevice) << endl;
263 
264  QCOL(cout, colW, CLI::tr("Output device:"));
265  cout << QString::fromStdString(args.outputDevice) << endl;
266  }
267 }
268 
269 #endif // END HULA_CLI_COMMON_H
<hlcontrol/hlcontrol.h>
Device * findDevice(Transport *t, const std::string &name, DeviceType type)
Utility function for searching the list of devices.
Definition: CLICommon.h:175
Extra class for managing the state of the application and all audio related processes.
Definition: Transport.h:33
std::string inputDevice
Store the input device name parsed from the CLI flags.
Definition: CLICommon.h:101
Controller * getController() const
Get the controller instance.
Definition: Transport.cpp:181
<hlaudio/hlaudio.h>
Definition: CLICommon.h:49
static void deleteDevices(std::vector< Device * > devices)
Delete all the device pointers inside the vector.
Definition: Device.cpp:54
std::vector< Device * > getDevices(DeviceType type) const
Fetch a list of devices for the given DeviceType.
Definition: Controller.cpp:116
std::string outputFilePath
Store the output file path parsed from the CLI flags.
Definition: CLICommon.h:93
static HulaSettings * getInstance()
Retreive the singular instance of HulaSettings or construct a new one if none exists.
Definition: HulaSettings.cpp:31
std::string outputDevice
Store the output device name parsed from the CLI flags.
Definition: CLICommon.h:109
void printDeviceList(Transport *t)
Utility CLI function to print the device list to the console.
Definition: CLICommon.h:117
void printSettings(const HulaImmediateArgs &args)
Utility function for printing the current application settings.
Definition: CLICommon.h:229
int getSampleRate()
Get the number of channels for the current global device configuration.
Definition: HulaAudioSettings.cpp:71
Wrapper for OS specific device information.
Definition: Device.h:55
Wrapper around translation functions for Qt.
Definition: Controller.h:10
Singleton class containing all settings for the application.
Definition: HulaSettings.h:23
bool getShowRecordDevices()
Getters.
Definition: HulaAudioSettings.cpp:45
DeviceType
Denotes type of Device.
Definition: Device.h:18
Args parsed from CLI flags.
Definition: CLICommon.h:56
struct hula::HulaImmediateArgs HulaImmediateArgs
Args parsed from CLI flags.
std::string delay
Store the delay as a string to be converted by InteractiveCLI.
Definition: CLICommon.h:74
std::string duration
Store the record duration as a string to be converted by InteractiveCLI.
Definition: CLICommon.h:85