2025-09-13 Fred Gleason <fredg@paravelsystems.com>

* Fixed a bug in rdalsaconfig(8) that caused multiple card entries
	to appear for sound devices with more than one PCM.

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
Fred Gleason 2025-09-13 18:46:08 -04:00
parent 9482446a6d
commit 62c3f7e5b7
8 changed files with 50 additions and 245 deletions

View File

@ -25045,3 +25045,6 @@
2025-09-13 Fred Gleason <fredg@paravelsystems.com>
* Fixed a bug in 'RDConfig' that caused a false 'invalid dropbox ID'
warning to be generated when parsing rd.conf(5).
2025-09-13 Fred Gleason <fredg@paravelsystems.com>
* Fixed a bug in rdalsaconfig(8) that caused multiple card entries
to appear for sound devices with more than one PCM.

View File

@ -2,7 +2,7 @@
//
// QListBoxItem for ALSA PCM devices.
//
// (C) Copyright 2009-2021 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2009-2025 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -24,14 +24,12 @@ AlsaItem::AlsaItem(const QString &text)
: QListWidgetItem(text)
{
alsa_card_number=-1;
alsa_pcm_number=-1;
}
AlsaItem::AlsaItem(const AlsaItem &item)
{
setCardNumber(item.cardNumber());
setPcmNumber(item.pcmNumber());
}
@ -45,15 +43,3 @@ void AlsaItem::setCardNumber(int cardnum)
{
alsa_card_number=cardnum;
}
int AlsaItem::pcmNumber() const
{
return alsa_pcm_number;
}
void AlsaItem::setPcmNumber(int pcmnum)
{
alsa_pcm_number=pcmnum;
}

View File

@ -2,7 +2,7 @@
//
// QListBoxItem for ALSA PCM devices.
//
// (C) Copyright 2009-2021 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2009-2025 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -30,12 +30,9 @@ class AlsaItem : public QListWidgetItem
AlsaItem(const AlsaItem &item);
int cardNumber() const;
void setCardNumber(int cardnum);
int pcmNumber() const;
void setPcmNumber(int pcmnum);
private:
int alsa_card_number;
int alsa_pcm_number;
};

View File

@ -2,7 +2,7 @@
//
// Abstract ALSA 'card' information
//
// (C) Copyright 2019-2021 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2019-2025 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -24,7 +24,6 @@ RDAlsaCard::RDAlsaCard(snd_ctl_t *ctl,int index)
{
snd_ctl_card_info_t *card_info;
snd_pcm_info_t *pcm_info;
int pcm=0;
card_index=index;
@ -37,15 +36,12 @@ RDAlsaCard::RDAlsaCard(snd_ctl_t *ctl,int index)
card_name=QString(snd_ctl_card_info_get_name(card_info));
card_long_name=QString(snd_ctl_card_info_get_longname(card_info));
card_mixer_name=QString(snd_ctl_card_info_get_mixername(card_info));
if(snd_ctl_pcm_info(ctl,pcm_info)==0) {
pcm=0;
while(pcm>=0) {
card_pcm_names.push_back(snd_pcm_info_get_name(pcm_info)+
QString::asprintf("[%02d]",pcm+1));
snd_ctl_pcm_next_device(ctl,&pcm);
card_enableds.push_back(false);
}
if(card_name=="Loopback") { // Fix the opaque name assigned by Wheatstone
card_name.replace("Loopback","WheatNet");
card_long_name.replace("Loopback","WheatNet");
card_mixer_name.replace("Loopback","WheatNet");
}
card_enabled=false;
snd_pcm_info_free(pcm_info);
snd_ctl_card_info_free(card_info);
}
@ -87,15 +83,15 @@ QString RDAlsaCard::mixerName() const
}
bool RDAlsaCard::isEnabled(int pcm_num) const
bool RDAlsaCard::isEnabled() const
{
return card_enableds.at(pcm_num);
return card_enabled;
}
void RDAlsaCard::setEnabled(int pcm_num,bool state)
void RDAlsaCard::setEnabled(bool state)
{
card_enableds[pcm_num]=state;
card_enabled=state;
}
@ -107,21 +103,6 @@ QString RDAlsaCard::dump() const
ret+=" Name: "+name()+"\n";
ret+=" LongName: "+longName()+"\n";
ret+=" MixerName: "+mixerName()+"\n";
for(int i=0;i<pcmQuantity();i++) {
ret+=QString::asprintf(" PCM[%d]: ",i)+pcmName(i)+"\n";
}
return ret;
}
int RDAlsaCard::pcmQuantity() const
{
return card_pcm_names.size();
}
QString RDAlsaCard::pcmName(int n) const
{
return card_pcm_names.at(n);
}

View File

@ -2,7 +2,7 @@
//
// Abstract ALSA 'card' information
//
// (C) Copyright 2019 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2019-2025 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -36,10 +36,8 @@ class RDAlsaCard
QString name() const;
QString longName() const;
QString mixerName() const;
int pcmQuantity() const;
QString pcmName(int n) const;
bool isEnabled(int pcm_num) const;
void setEnabled(int pcm_num,bool state);
bool isEnabled() const;
void setEnabled(bool state);
QString dump() const;
private:
@ -49,8 +47,7 @@ class RDAlsaCard
QString card_name;
QString card_long_name;
QString card_mixer_name;
QStringList card_pcm_names;
QList<bool> card_enableds;
bool card_enabled;
};

View File

@ -2,7 +2,7 @@
//
// A Qt-based application to display info about ALSA cards.
//
// (C) Copyright 2009-2021 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2009-2025 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -224,88 +224,6 @@ void MainWidget::LoadConfig(const QString &filename)
select(alsa_system_model->index(i,0),QItemSelectionModel::Deselect);
}
}
/*
FILE *f=NULL;
char line[1024];
int istate=0;
int port=0;
QString card_id=0;
int device=0;
QStringList list;
bool active_line=false;
QModelIndex index;
if((f=fopen(filename.toUtf8(),"r"))==NULL) {
return;
}
while(fgets(line,1024,f)!=NULL) {
QString str=line;
str.replace("\n","");
if(str==START_MARKER) {
active_line=true;
}
if(str==END_MARKER) {
active_line=false;
}
if((str!=START_MARKER)&&(str!=END_MARKER)) {
if(active_line) {
switch(istate) {
case 0:
if(str.left(6)=="pcm.rd") {
port=str.mid(6,1).toInt();
istate=1;
}
else {
if(str.left(6)=="ctl.rd") {
istate=10;
}
else {
alsa_other_lines.push_back(str+"\n");
}
}
break;
case 1:
list=str.split(" ",QString::SkipEmptyParts);
if(list[0]=="}") {
if((port>=0)&&(port<RD_MAX_CARDS)) {
index=alsa_system_model->indexOf(card_id,device);
if(index.isValid()) {
alsa_system_list->selectionModel()->
select(index,QItemSelectionModel::Select);
}
}
card_id="";
device=0;
istate=0;
}
else {
if(list.size()==2) {
if(list[0]=="card") {
card_id=list[1].trimmed();
}
if(list[0]=="device") {
device=list[1].toInt();
}
}
}
break;
case 10:
if(str.left(1)=="}") {
istate=0;
}
break;
}
}
else {
alsa_other_lines.push_back(str+"\n");
}
}
}
fclose(f);
*/
}
@ -316,42 +234,6 @@ void MainWidget::SaveConfig(const QString &filename) const
alsa_system_model->setEnabled(i,sel->isRowSelected(i,QModelIndex()));
}
alsa_system_model->saveConfig(filename);
/*
QString tempfile=filename+"-temp";
FILE *f=NULL;
if((f=fopen(tempfile.toUtf8(),"w"))==NULL) {
return;
}
for(int i=0;i<alsa_other_lines.size();i++) {
fprintf(f,alsa_other_lines.at(i));
}
fprintf(f,"%s\n",START_MARKER);
QModelIndexList indexes=alsa_system_list->selectionModel()->selectedIndexes();
for(int i=0;i<indexes.size();i++) {
fprintf(f,"pcm.rd%d {\n",i);
fprintf(f," type hw\n");
fprintf(f," card %s\n",
(const char *)alsa_system_model->card(indexes.at(i))->id().toUtf8());
fprintf(f," device %d\n",alsa_system_model->pcmNumber(indexes.at(i)));
fprintf(f," rate %u\n",rda->system()->sampleRate());
if(alsa_system_model->card(indexes.at(i))->id()=="Axia") {
fprintf(f," channels 2\n");
}
fprintf(f,"}\n");
fprintf(f,"ctl.rd%d {\n",i);
fprintf(f," type hw\n");
fprintf(f," card %s\n",
(const char *)alsa_system_model->card(indexes.at(i))->id().toUtf8());
fprintf(f,"}\n");
}
fprintf(f,"%s\n",END_MARKER);
fclose(f);
rename(tempfile.toUtf8(),filename.toUtf8());
*/
}

View File

@ -2,7 +2,7 @@
//
// Abstract an ALSA configuration.
//
// (C) Copyright 2009-2021 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2009-2025 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -32,13 +32,7 @@ RDAlsaModel::RDAlsaModel(unsigned samprate,QObject *parent)
int RDAlsaModel::rowCount(const QModelIndex &parent) const
{
int rows=0;
for(int i=0;i<model_alsa_cards.size();i++) {
rows+=model_alsa_cards.at(i)->pcmQuantity();
}
return rows;
return model_alsa_cards.size();
}
@ -46,7 +40,7 @@ Qt::ItemFlags RDAlsaModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags=QAbstractListModel::flags(index);
if((model_alsa_cards.at(model_card_index.at(index.row()))->id()=="Axia")&&
if((model_alsa_cards.at(index.row())->id()=="Axia")&&
(model_sample_rate!=48000)) {
flags=flags&Qt::ItemIsEnabled;
}
@ -61,9 +55,7 @@ QVariant RDAlsaModel::data(const QModelIndex &index,int role) const
switch((Qt::ItemDataRole)role) {
case Qt::DisplayRole:
return QVariant(model_alsa_cards.at(model_card_index.at(row))->name()+" - "+
model_alsa_cards.at(model_card_index.at(row))->
pcmName(model_pcm_index.at(row)));
return QVariant(model_alsa_cards.at(row)->longName());
break;
case Qt::DecorationRole:
@ -108,23 +100,13 @@ QVariant RDAlsaModel::headerData(int section,Qt::Orientation orient,
}
QModelIndex RDAlsaModel::indexOf(const QString &card_id,int pcm_num) const
QModelIndex RDAlsaModel::indexOf(const QString &card_id) const
{
bool ok=false;
int cardnum=card_id.toUInt(&ok);
if(ok) {
for(int i=0;i<model_card_index.size();i++) {
if((model_card_index.at(i)==cardnum)&&
(model_pcm_index.at(i)==pcm_num)) {
return createIndex(i,0);
}
}
}
else {
for(int i=0;i<model_card_index.size();i++) {
if((model_alsa_cards.at(model_card_index.at(i))->id()==card_id)&&
(model_pcm_index.at(i)==pcm_num)) {
for(int i=0;i<model_alsa_cards.size();i++) {
if(model_alsa_cards.at(i)->id()==card_id) {
return createIndex(i,0);
}
}
@ -134,29 +116,15 @@ QModelIndex RDAlsaModel::indexOf(const QString &card_id,int pcm_num) const
}
RDAlsaCard *RDAlsaModel::card(const QModelIndex &index) const
{
return model_alsa_cards.at(model_card_index.at(index.row()));
}
int RDAlsaModel::pcmNumber(const QModelIndex &index) const
{
return model_pcm_index.at(index.row());
}
bool RDAlsaModel::isEnabled(int row) const
{
return model_alsa_cards.at(model_card_index.at(row))->
isEnabled(model_pcm_index.at(row));
return model_alsa_cards.at(row)->isEnabled();
}
void RDAlsaModel::setEnabled(int row,bool state)
{
return model_alsa_cards.at(model_card_index.at(row))->
setEnabled(model_pcm_index.at(row),state);
return model_alsa_cards.at(row)->setEnabled(state);
}
@ -213,15 +181,15 @@ bool RDAlsaModel::loadConfig(const QString &filename)
card_num=card_id.toUInt(&ok);
if(ok) {
if(card_num==card->index()) {
if((device>=0)&&(device<card->pcmQuantity())) {
card->setEnabled(device,true);
if(device>=0) {
card->setEnabled(true);
}
}
}
else {
if(card_id==card->id()) {
if((device>=0)&&(device<card->pcmQuantity())) {
card->setEnabled(device,true);
if(device>=0) {
card->setEnabled(true);
}
}
}
@ -276,12 +244,11 @@ bool RDAlsaModel::saveConfig(const QString &filename)
fprintf(f,"%s\n",START_MARKER);
for(int i=0;i<model_alsa_cards.size();i++) {
RDAlsaCard *card=model_alsa_cards.at(i);
for(int j=0;j<card->pcmQuantity();j++) {
if(card->isEnabled(j)) {
if(card->isEnabled()) {
fprintf(f,"pcm.rd%d {\n",index);
fprintf(f," type hw\n");
fprintf(f," card %s\n",(const char *)card->id().toUtf8());
fprintf(f," device %d\n",j);
fprintf(f," device 0\n");
fprintf(f," rate %u\n",rda->system()->sampleRate());
if(card->id()=="Axia") {
fprintf(f," channels 2\n");
@ -294,7 +261,6 @@ bool RDAlsaModel::saveConfig(const QString &filename)
index++;
}
}
}
fprintf(f,"%s\n",END_MARKER);
fclose(f);
@ -311,10 +277,7 @@ void RDAlsaModel::LoadSystemConfig()
while(snd_ctl_open(&snd_ctl,QString::asprintf("hw:%d",index).toUtf8(),0)>=0) {
model_alsa_cards.push_back(new RDAlsaCard(snd_ctl,index));
for(int i=0;i<model_alsa_cards.back()->pcmQuantity();i++) {
model_card_index.push_back(index);
model_pcm_index.push_back(i);
}
printf("[%d]: %s\n\n",index,model_alsa_cards.back()->dump().toUtf8().constData());
snd_ctl_close(snd_ctl);
index++;
}

View File

@ -2,7 +2,7 @@
//
// Abstract an ALSA configuration.
//
// (C) Copyright 2009-2018 Fred Gleason <fredg@paravelsystems.com>
// (C) Copyright 2009-2025 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@ -42,9 +42,7 @@ class RDAlsaModel : public QAbstractListModel
QVariant data(const QModelIndex &index,int role=Qt::DisplayRole) const;
QVariant headerData(int section,Qt::Orientation orient,
int role=Qt::DisplayRole) const;
QModelIndex indexOf(const QString &card_id,int pcm_num) const;
RDAlsaCard *card(const QModelIndex &index) const;
int pcmNumber(const QModelIndex &index) const;
QModelIndex indexOf(const QString &card_id) const;
bool isEnabled(int row) const;
void setEnabled(int row,bool state);
bool loadConfig(const QString &filename);
@ -53,8 +51,6 @@ class RDAlsaModel : public QAbstractListModel
private:
void LoadSystemConfig();
QList<RDAlsaCard *> model_alsa_cards;
QList<int> model_card_index;
QList<int> model_pcm_index;
unsigned model_sample_rate;
QStringList model_other_lines;
};