#include <QCommandLineParser>
#include <QStringList>
#include <QTextStream>
#include <QIODevice>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
#define right Qt::right
#define left Qt::left
#define endl Qt::endl
#define hex Qt::hex
#define dec Qt::dec
#endif
QString PGM_NAME = QStringLiteral("drumstick-sysinfo");
QString PGM_DESCRIPTION = QStringLiteral("ALSA Sequencer System Info");
QTextStream cout(stdout, QIODevice::WriteOnly);
QTextStream cerr(stderr, QIODevice::WriteOnly);
void queryTimers()
{
cout << endl << "ALSA Timers" << endl;
TimerQuery* query = new TimerQuery("hw", 0);
cout << "type___ Name________________ c/s/C/D/S Freq." << endl;
TimerIdList::ConstIterator it;
for( it = lst.constBegin(); it != lst.constEnd(); ++it )
{
TimerId id = *it;
try {
Timer* timer = new Timer(id, SND_TIMER_OPEN_NONBLOCK);
TimerInfo info = timer->getTimerInfo();
cout << qSetFieldWidth(8) << left << info.getId()
<< qSetFieldWidth(20) << left << info.getName().leftJustified(20, ' ', true)
<< qSetFieldWidth(0) << " "
<< id.getClass() << "/" << id.getSlaveClass() << "/"
<< id.getCard() << "/" << id.getDevice() << "/"
<< id.getSubdevice() << " ";
if( info.isSlave() ) {
cout << "SLAVE";
} else {
long freq = info.getFrequency();
cout << freq << " Hz";
}
cout << endl;
delete timer;
} catch (const SequencerError& err) {
cerr << "Error opening timer:" << err.qstrError();
}
}
delete query;
}
void queryQueues(MidiClient* c)
{
cout << endl << "ALSA Queues" << endl;
cout << "id Queue_Name__________ Timer_Name__________ owner status "
<< " state PPQ Tempo BPM Ticks Time" << endl;
QList<int> queues = c->getAvailableQueues();
foreach( int q, queues ) {
MidiQueue* queue = new MidiQueue(c, q);
if (queue != nullptr) {
QueueInfo qinfo = queue->getInfo();
QueueStatus qsts = queue->getStatus();
QueueTempo qtmp = queue->getTempo();
QueueTimer qtmr = queue->getTimer();
TimerId tid(qtmr.getId());
QString tname;
try {
Timer* timer = new Timer(tid, SND_TIMER_OPEN_NONBLOCK);
TimerInfo tinfo = timer->getTimerInfo();
tname = tinfo.getName();
delete timer;
} catch (...) {
tname = "inaccessible";
}
cout << qSetFieldWidth(3) << left << qinfo.getId()
<< qSetFieldWidth(20) << qinfo.getName().leftJustified(20, ' ', true)
<< qSetFieldWidth(0) << " "
<< qSetFieldWidth(20) << tname.leftJustified(20, ' ', true)
<< qSetFieldWidth(6) << right << qinfo.getOwner()
<< qSetFieldWidth(7) << (qinfo.isLocked() ? "locked" : "free")
<< qSetFieldWidth(8) << (qsts.isRunning() ? "running" : "stopped")
<< qSetFieldWidth(4) << qtmp.getPPQ()
<< qSetFieldWidth(7) << qtmp.getRealBPM()
<< qSetFieldWidth(4) << qtmp.getNominalBPM()
<< qSetFieldWidth(8) << qsts.getTickTime()
<< qSetFieldWidth(0) << " " << qsts.getClockTime()
<< endl;
delete queue;
}
}
}
QString clientTypeName(snd_seq_client_type_t ctype)
{
if (ctype == SND_SEQ_USER_CLIENT)
return "User";
if (ctype == SND_SEQ_KERNEL_CLIENT)
return "Kernel";
return "Unknown";
}
QString portTypeNames(int ptype)
{
QStringList lst;
if ((ptype & SND_SEQ_PORT_TYPE_HARDWARE) != 0)
lst << "Hardware";
if ((ptype & SND_SEQ_PORT_TYPE_SOFTWARE) != 0)
lst << "Software";
if ((ptype & SND_SEQ_PORT_TYPE_PORT) != 0)
lst << "Port";
if ((ptype & SND_SEQ_PORT_TYPE_DIRECT_SAMPLE) != 0)
lst << "Direct Sample";
if ((ptype & SND_SEQ_PORT_TYPE_MIDI_GENERIC) != 0)
lst << "MIDI Generic";
if ((ptype & SND_SEQ_PORT_TYPE_MIDI_GM) != 0)
lst << "GM";
if ((ptype & SND_SEQ_PORT_TYPE_MIDI_GM2) != 0)
lst << "GM2";
if ((ptype & SND_SEQ_PORT_TYPE_MIDI_GS) != 0)
lst << "GS";
if ((ptype & SND_SEQ_PORT_TYPE_MIDI_MT32) != 0)
lst << "MT32";
if ((ptype & SND_SEQ_PORT_TYPE_MIDI_XG) != 0)
lst << "XG";
if ((ptype & SND_SEQ_PORT_TYPE_SAMPLE) != 0)
lst << "Sample";
if ((ptype & SND_SEQ_PORT_TYPE_SPECIFIC) != 0)
lst << "Specific";
if ((ptype & SND_SEQ_PORT_TYPE_SYNTH) != 0)
lst << "Synth";
if ((ptype & SND_SEQ_PORT_TYPE_APPLICATION) != 0)
lst << "Application";
if ((ptype & SND_SEQ_PORT_TYPE_SYNTHESIZER) != 0)
lst << "Synthesizer";
return " (" + lst.join(", ") + ")";
}
{
QStringList lst;
foreach( Subscriber s, subs ) {
QString sname = QString("%1:%2").arg(static_cast<int>(s.getAddr()->client))
.arg(static_cast<int>(s.getAddr()->port));
lst << sname;
}
return lst.join(", ");
}
void queryClients(MidiClient* c)
{
cout << endl << "ALSA Sequencer clients" << endl;
foreach( ClientInfo cinfo, clients ) {
cout << "Client " << qSetFieldWidth(4) << left << cinfo.getClientId()
<< qSetFieldWidth(0) << " : \"" << cinfo.getName() << "\" ["
<< clientTypeName(cinfo.getClientType())
<< "]" << endl;
foreach( PortInfo pinfo, plist ) {
cout << " Port " << qSetFieldWidth(4) << right << pinfo.getPort()
<< qSetFieldWidth(0) << " : \"" << pinfo.getName() << "\""
<< (pinfo.getType() != 0 ? portTypeNames(pinfo.getType()) : "")
<< endl;
if ( from.count() > 0 )
cout << " Connected From: " << subsNames(from) << endl;
if ( to.count() > 0 )
cout << " Connecting To: " << subsNames(to) << endl;
}
}
}
void systemInfo()
{
MidiClient* client = new MidiClient();
client->open();
client->setClientName(PGM_NAME);
SystemInfo info = client->getSystemInfo();
cout << PGM_DESCRIPTION << ", version: "<< QStringLiteral(QT_STRINGIFY(VERSION)) << endl;
cout << "Runtime ALSA library: "
<< getRuntimeALSALibraryVersion() << endl;
cout << "Runtime ALSA drivers: "
cout << "Numeric ALSA compiled library: "
<< hex << SND_LIB_VERSION << endl;
cout << "Numeric ALSA runtime library: "
<< getRuntimeALSALibraryNumber() << endl;
cout << "Numeric ALSA runtime driver: "
cout << "Max Clients: " << dec << info.getMaxClients() << endl;
cout << "Max Ports: " << info.getMaxPorts() << endl;
cout << "Max Queues: " << info.getMaxQueues() << endl;
cout << "Max Channels: " << info.getMaxChannels() << endl;
cout << "Current Queues: " << info.getCurrentQueues() << endl;
cout << "Current Clients: " << info.getCurrentClients() << endl;
queryTimers();
if (info.getCurrentQueues() > 0)
queryQueues(client);
if (info.getCurrentClients() > 0)
queryClients(client);
delete client;
}
int main(int argc, char **argv)
{
const QString ERRORSTR = QStringLiteral("Fatal error from the ALSA sequencer. "
"This usually happens when the kernel doesn't have ALSA support, "
"or the device node (/dev/snd/seq) doesn't exists, "
"or the kernel module (snd_seq) is not loaded. "
"Please check your ALSA/MIDI configuration.");
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName(PGM_NAME);
QCoreApplication::setApplicationVersion(QStringLiteral(QT_STRINGIFY(VERSION)));
QCommandLineParser parser;
parser.setApplicationDescription(PGM_DESCRIPTION);
auto helpOption = parser.addHelpOption();
auto versionOption = parser.addVersionOption();
parser.process(app);
if (parser.isSet(versionOption) || parser.isSet(helpOption)) {
return 0;
}
try {
systemInfo();
} catch (const SequencerError& ex) {
cerr << ERRORSTR << " Returned error was: " << ex.qstrError() << endl;
} catch (...) {
cerr << ERRORSTR << endl;
}
return 0;
}
Classes managing ALSA Sequencer clients.
Classes managing ALSA Sequencer queues.
Classes managing ALSA Timers.
int getRuntimeALSADriverNumber()
Gets the runtime ALSA drivers version number.
QList< ClientInfo > ClientInfoList
List of sequencer client information.
QString getRuntimeALSADriverVersion()
Gets the runtime ALSA drivers version string.
QString getCompiledALSALibraryVersion()
ALSA library version at build time.
QList< PortInfo > PortInfoList
List of port information objects.
QList< Subscriber > SubscribersList
List of subscribers.
QList< TimerId > TimerIdList
List of timer identifiers.
Drumstick ALSA library wrapper.
SequencerError Exception class.
Classes managing ALSA sequencer subscriptions.