Tuner display

This commit is contained in:
Robin Davies
2022-07-05 09:33:37 -04:00
parent 95e5cd1301
commit 2133403f7e
10 changed files with 426 additions and 260 deletions
+105 -15
View File
@@ -23,6 +23,7 @@
*/
#include "CommandLineParser.hpp"
#include "ss.hpp"
#include "PrettyPrinter.hpp"
#include <iostream>
#include "PiPedalAlsa.hpp"
@@ -40,7 +41,8 @@ constexpr int E_XRUN = 3;
constexpr uint64_t NO_SIGNAL_VALUE = 0x7000000;
struct TestResult {
struct TestResult
{
int error = 0;
uint64_t latency = 0;
float cpuOverhead = 0;
@@ -62,6 +64,11 @@ void PrintHelp()
<< "List available devices.\n\n";
pp << HangingIndent() << " -r --rate\t"
<< "Sample rate (default 48000).\n\n";
pp << HangingIndent() << " -i --in_channels\t"
<< "Input channels. Command-seperated list. e.g.: 0,3. Default: all channels.\n\n";
pp << HangingIndent() << " -o --out_channels\t"
<< "Output channels. Command-seperated list. e.g.: 0,1,4. Default: all channels.\n\n";
pp << HangingIndent() << " -h --help\t"
<< "Display this message.\n\n";
@@ -107,6 +114,9 @@ void ListDevices()
}
}
using ChannelsT = std::vector<int>;
class AlsaTester : private AudioDriverHost
{
public:
@@ -121,14 +131,22 @@ private:
AudioDriver *audioDriver = nullptr;
const std::string &deviceId;
ChannelsT inputChannels;
ChannelsT outputChannels;
uint32_t sampleRate;
int bufferSize;
int buffers;
public:
AlsaTester(const std::string &deviceId, uint32_t sampleRate, int bufferSize, int buffers)
AlsaTester(
const std::string &deviceId,
const ChannelsT &inputChannels,
const ChannelsT &outputChannels,
uint32_t sampleRate, int bufferSize, int buffers)
: deviceId(deviceId),
sampleRate(sampleRate),
inputChannels(inputChannels),
outputChannels(outputChannels),
bufferSize(bufferSize),
buffers(buffers)
{
@@ -139,6 +157,21 @@ public:
delete[] inputBuffers;
delete[] outputBuffers;
}
std::vector<std::string> SelectChannels(const std::vector<std::string>&available, const std::vector<int>& selection)
{
if (selection.size() == 0) return available;
std::vector<std::string> result;
for (int sel: selection)
{
if (sel < 0 || sel >= available.size())
{
throw PiPedalArgumentException(SS("Invalid channel: " + sel));
}
result.push_back(available[sel]);
}
return result;
}
TestResult Test()
{
@@ -150,9 +183,17 @@ public:
JackConfiguration jackConfiguration;
jackConfiguration.AlsaInitialize(serverSettings);
auto & availableInputs = jackConfiguration.GetInputAudioPorts();
auto & availableOutputs = jackConfiguration.GetOutputAudioPorts();
std::vector<std::string> inputAudioPorts, outputAudioPorts;
inputAudioPorts = SelectChannels(availableInputs,this->inputChannels);
outputAudioPorts = SelectChannels(availableOutputs,this->outputChannels);
JackChannelSelection channelSelection(
jackConfiguration.GetInputAudioPorts(),
jackConfiguration.GetOutputAudioPorts(),
inputAudioPorts, outputAudioPorts,
std::vector<AlsaMidiDeviceInfo>());
audioDriver = CreateAlsaDriver(this);
@@ -176,11 +217,11 @@ public:
if (this->GetXruns() != 0)
{
result.error = E_XRUN;
result.error = E_XRUN;
return result;
}
result.latency = latencyMonitor.GetLatency();
if (result.latency == NO_SIGNAL_VALUE)
result.latency = latencyMonitor.GetLatency();
if (result.latency == NO_SIGNAL_VALUE)
{
result.error = E_NOSIGNAL;
}
@@ -267,7 +308,7 @@ public:
state = State::Waiting;
current_latency = 0;
}
return 0.01;
return 0.001;
}
break;
case State::Waiting:
@@ -349,9 +390,13 @@ public:
}
};
TestResult RunLatencyTest(const std::string deviceId, uint32_t sampleRate, int bufferSize, int buffers)
TestResult RunLatencyTest(
const std::string deviceId,
const ChannelsT &inputChannels,
const ChannelsT &outputChannels,
uint32_t sampleRate, int bufferSize, int buffers)
{
AlsaTester tester(deviceId, sampleRate, bufferSize, buffers);
AlsaTester tester(deviceId, inputChannels, outputChannels, sampleRate, bufferSize, buffers);
return tester.Test();
}
@@ -360,7 +405,7 @@ static std::string msDisplay(float value)
std::stringstream s;
s << fixed;
s.precision(1);
s << value << "ms";
s << value << "ms";
return s.str();
}
static std::string overheadDisplay(float value)
@@ -370,7 +415,11 @@ static std::string overheadDisplay(float value)
return s.str();
}
void RunLatencyTest(const std::string &deviceId, uint32_t sampleRate)
void RunLatencyTest(
const std::string &deviceId,
const ChannelsT &inputChannels,
const ChannelsT &outputChannels,
uint32_t sampleRate)
{
PrettyPrinter pp;
pp << "Device: " << deviceId << " Rate: " << sampleRate << "\n\n";
@@ -400,7 +449,7 @@ void RunLatencyTest(const std::string &deviceId, uint32_t sampleRate)
for (auto bufferCount : bufferCounts)
{
auto result = RunLatencyTest(deviceId, sampleRate, bufferSize, bufferCount);
auto result = RunLatencyTest(deviceId, inputChannels,outputChannels, sampleRate, bufferSize, bufferCount);
pp.Column(column);
column += BUFFERS_COLUMN_WIDTH;
@@ -419,7 +468,7 @@ void RunLatencyTest(const std::string &deviceId, uint32_t sampleRate)
default:
{
float ms = 1000.0f * result.latency / sampleRate;
pp << result.latency << "/" << msDisplay(ms) ;
pp << result.latency << "/" << msDisplay(ms);
break;
}
}
@@ -428,6 +477,39 @@ void RunLatencyTest(const std::string &deviceId, uint32_t sampleRate)
}
}
ChannelsT ParseChannels(const std::string&channels)
{
ChannelsT result;
std::stringstream s(channels);
while (true)
{
int c = s.peek();
if (c == -1) break;
if (c == ',') {
s.get();
c = s.peek();
}
if (c < '0' || c > '9')
{
throw PiPedalArgumentException("Invalid channel selection: " + channels);
}
int v = 0;
while (s.peek() >= '0' && s.peek() <= '9')
{
c = s.get();
v = v*10 + c-'0';
}
result.push_back(v);
}
return result;
}
int main(int argc, const char **argv)
{
@@ -439,10 +521,16 @@ int main(int argc, const char **argv)
bool listDevices = false;
bool help = false;
uint32_t sampleRate = 48000;
std:
string strInputChannels, strOutputChannels;
ChannelsT inputChannels, outputChannels;
parser.AddOption("l", "list", &listDevices);
parser.AddOption("h", "help", &help);
parser.AddOption("r", "rate", &sampleRate);
parser.AddOption("i", "in_channels", &strInputChannels);
parser.AddOption("o", "out_channels", &strOutputChannels);
try
{
@@ -458,7 +546,9 @@ int main(int argc, const char **argv)
}
else if (parser.Arguments().size() == 1)
{
RunLatencyTest(parser.Arguments()[0], sampleRate);
inputChannels = ParseChannels(strInputChannels);
outputChannels = ParseChannels(strInputChannels);
RunLatencyTest(parser.Arguments()[0], inputChannels, outputChannels, sampleRate);
}
else
{