#include <QCommandLineParser>
#include <QStringList>
#include <QTextStream>
#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.
QString getRuntimeALSADriverVersion()
Gets the runtime ALSA drivers version string.
QList< ClientInfo > ClientInfoList
List of sequencer client information.
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.