// rdsound_panel.cpp // // The sound panel widget. // // (C) Copyright 2002-2024 Fred Gleason // // 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 // published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public // License along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // #include #include #include #include "rdapplication.h" #include "rdbutton_dialog.h" #include "rdcut.h" #include "rdconf.h" #include "rddb.h" #include "rdedit_panel_name.h" #include "rdescape_string.h" #include "rdlog_line.h" #include "rdmacro.h" #include "rdsound_panel.h" RDSoundPanel::RDSoundPanel(int station_panels,int user_panels,bool flash, const QString &caption,const QString &label_template, bool extended,RDEventPlayer *player, RDCartDialog *cart_dialog,QWidget *parent) : RDWidget(parent) { panel_started=false; panel_current_panel=NULL; panel_dump_panel_updates=false; panel_playmode_box=NULL; panel_button_columns=PANEL_MAX_BUTTON_COLUMNS; panel_button_rows=PANEL_MAX_BUTTON_ROWS; panel_cue_port=-1; panel_caption=caption; if(extended) { panel_tablename="`EXTENDED_PANELS`"; panel_name_tablename="`EXTENDED_PANEL_NAMES`"; } else { panel_tablename="`PANELS`"; panel_name_tablename="`PANEL_NAMES`"; } panel_label_template=label_template; panel_type=RDAirPlayConf::StationPanel; panel_number=0; panel_setup_mode=false; panel_reset_mode=false; panel_parent=parent; panel_station_panels=station_panels; panel_user_panels=user_panels; panel_event_player=player; panel_action_mode=RDAirPlayConf::Normal; for(int i=0;isetFont(buttonFont()); panel_selector_box->addIgnoredKey(Qt::Key_Space); connect(panel_selector_box,SIGNAL(activated(int)), this,SLOT(panelActivatedData(int))); connect(panel_selector_box,SIGNAL(setupClicked()), this,SLOT(panelSetupData())); // // Play Mode Box // panel_playmode_box=new QComboBox(this); panel_playmode_box->setFont(buttonFont()); connect(panel_playmode_box,SIGNAL(activated(int)), this,SLOT(playmodeActivatedData(int))); panel_playmode_box->insertItem(panel_playmode_box->count(),tr("Play All")); panel_playmode_box->insertItem(panel_playmode_box->count(),tr("Play Hook")); // // Reset Button // panel_reset_button=new RDPushButton(this); panel_reset_button->setFont(buttonFont()); panel_reset_button->setText(tr("Reset")); panel_reset_button->setFlashColor(QColor(RDPANEL_RESET_FLASH_COLOR)); panel_reset_button->setFocusPolicy(Qt::NoFocus); connect(panel_reset_button,SIGNAL(clicked()),this,SLOT(resetClickedData())); // // All Button // panel_all_button=new RDPushButton(this); panel_all_button->setFont(buttonFont()); panel_all_button->setText(tr("All")); panel_all_button->setFlashColor(QColor(RDPANEL_RESET_FLASH_COLOR)); panel_all_button->setFocusPolicy(Qt::NoFocus); panel_all_button->hide(); connect(panel_all_button,SIGNAL(clicked()),this,SLOT(allClickedData())); // // Setup Button // panel_setup_button=new RDPushButton(this); panel_setup_button->setFont(buttonFont()); panel_setup_button->setText(tr("Setup")); panel_setup_button->setFlashColor(QColor(RDPANEL_SETUP_FLASH_COLOR)); panel_setup_button->setFocusPolicy(Qt::NoFocus); connect(panel_setup_button,SIGNAL(clicked()),this,SLOT(setupClickedData())); // // Button Dialog Box // panel_button_dialog= new RDButtonDialog(rda->station()->name(),panel_caption, panel_label_template,panel_cart_dialog,panel_svcname, this); // // CAE Setup // connect(rda->cae(),SIGNAL(timescalingSupported(int,bool)), this,SLOT(timescalingSupportedData(int,bool))); // // RIPC Setup // connect(rda->ripc(),SIGNAL(onairFlagChanged(bool)), this,SLOT(onairFlagChangedData(bool))); connect(rda->ripc(),SIGNAL(notificationReceived(RDNotification *)), this,SLOT(notificationReceivedData(RDNotification *))); // // Load Panel Names // QString sql; sql=QString("select ")+ "`PANEL_NO`,"+ // 00 "`NAME` "+ // 01 "from "+panel_name_tablename+" where "+ QString::asprintf("(`TYPE`=%d)&&",RDAirPlayConf::StationPanel)+ "(`OWNER`='"+RDEscapeString(rda->station()->name())+"') "+ "order by `PANEL_NO`"; RDSqlQuery *q=new RDSqlQuery(sql); q->first(); for(int i=0;iisValid()&&(q->value(0).toInt()==i)) { panel_selector_box-> insertItem(QString::asprintf("[S:%d] ",i+1)+q->value(1).toString()); q->next(); } else { panel_selector_box->insertItem(QString::asprintf("[S:%d] Panel S:%d", i+1,i+1)); } } delete q; for(int i=0;iinsertItem(QString::asprintf("[U:%d] Panel U:%d", i+1,i+1)); } panel_selector_box->setFocus(); setDisabled((panel_station_panels==0)&&(panel_user_panels==0)); } RDSoundPanel::~RDSoundPanel() { for(QMap >::const_iterator it=panel_arrays.begin();it!=panel_arrays.end();it++) { for(int i=0;icae()->requestTimescale(card); } int RDSoundPanel::port(int outnum) const { return panel_port[outnum]; } void RDSoundPanel::setPort(int outnum,int port) { panel_port[outnum]=port; } QString RDSoundPanel::outputText(int outnum) const { return panel_output_text[outnum]; } void RDSoundPanel::setOutputText(int outnum,const QString &text) { panel_output_text[outnum]=text; } void RDSoundPanel::setRmls(int outnum,const QString &start_rml, const QString &stop_rml) { panel_start_rml[outnum]=start_rml; panel_stop_rml[outnum]=stop_rml; } void RDSoundPanel::setSvcName(const QString &svcname) { panel_svcname=svcname; panel_svcname.replace(" ","_"); } void RDSoundPanel::play(RDAirPlayConf::PanelType type,int panel, int row, int col,RDLogLine::StartSource src,int mport, bool pause_when_finished) { PlayButton(type,panel,row,col,src,panel_playmode_box->currentIndex()==1, mport,pause_when_finished); } bool RDSoundPanel::pause(RDAirPlayConf::PanelType type,int panel, int row,int col,int mport) { if(panel_pause_enabled) { PauseButton(type,panel,row,col,mport); return true; } return false; } void RDSoundPanel::stop(RDAirPlayConf::PanelType type,int panel, int row,int col, int mport,bool pause_when_finished,int fade_out) { StopButton(type,panel,row,col,mport,pause_when_finished,fade_out); } void RDSoundPanel::channelStop(int mport) { RDPanelButton *button=NULL; RDPlayDeck *deck=NULL; for(unsigned i=0;ioutputText().toInt()==(mport+1)) { if((deck=button->playDeck())!=NULL) { if(deck->state()==RDPlayDeck::Playing) { deck->stop(); } } } } } } void RDSoundPanel::setText(RDAirPlayConf::PanelType type,int panel,int row, int col,const QString &str) { QString username; if(type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } RDPanelButton *button= panel_arrays.value(username).at(panel)->panelButton(row,col); button->setText(str); SaveButton(type,panel,row,col); } void RDSoundPanel::setColor(RDAirPlayConf::PanelType type,int panel,int row, int col,const QColor &color) { QString username; if(type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } RDPanelButton *button= panel_arrays.value(username).at(panel)->panelButton(row,col); button->setDefaultColor(color); SaveButton(type,panel,row,col); } void RDSoundPanel::duckVolume(RDAirPlayConf::PanelType type,int panel,int row, int col,int level,int fade,int mport) { QString username; if(type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } int edit_mport=mport; if (edit_mport==0) { edit_mport=-1; } for(int i=0;ipanelButton(j,i)->playDeck(); if((row==j || row==-1) && (col==i || col==-1)) { if(mport==-1) { panel_arrays.value(username).at(panel)-> panelButton(j,i)->setDuckVolume(level); } if(deck!=NULL) { if(edit_mport==-1 || edit_mport== panel_arrays.value(username).at(panel)-> panelButton(j,i)->outputText().toInt()) { deck->duckVolume(level,fade); } } } } } } RDAirPlayConf::ActionMode RDSoundPanel::actionMode() const { return panel_action_mode; } void RDSoundPanel::setActionMode(RDAirPlayConf::ActionMode mode) { if(panel_setup_mode) { return; } switch(mode) { case RDAirPlayConf::CopyFrom: mode=RDAirPlayConf::CopyFrom; break; case RDAirPlayConf::CopyTo: mode=RDAirPlayConf::CopyTo; break; case RDAirPlayConf::AddTo: mode=RDAirPlayConf::AddTo; break; case RDAirPlayConf::DeleteFrom: mode=RDAirPlayConf::DeleteFrom; break; default: mode=RDAirPlayConf::Normal; break; } if(mode!=panel_action_mode) { panel_action_mode=mode; panel_setup_button->setEnabled(panel_action_mode==RDAirPlayConf::Normal); for(QMap >::const_iterator it=panel_arrays.begin();it!=panel_arrays.end();it++) { for(int i=0;isetActionMode(RDAirPlayConf::Normal); } else { it.value().at(i)->setActionMode(panel_action_mode); } } } } } bool RDSoundPanel::pauseEnabled() const { return panel_pause_enabled; } void RDSoundPanel::setPauseEnabled(bool state) { if(state) { panel_reset_button->show(); } else { panel_reset_button->hide(); } panel_pause_enabled=state; } int RDSoundPanel::currentNumber() const { return panel_number; } RDAirPlayConf::PanelType RDSoundPanel::currentType() const { return panel_type; } QByteArray RDSoundPanel::json(const QString &owner) const { QJsonArray ja0; QList panels=panel_arrays.value(""); for(int i=0;ijson()); } panels=panel_arrays.value(rda->user()->name()); for(int i=0;ijson()); } QJsonObject jo0; jo0.insert("panels",ja0); QJsonDocument jdoc; jdoc.setObject(jo0); return jdoc.toJson(); } void RDSoundPanel::setButton(RDAirPlayConf::PanelType type,int panel, int row,int col,unsigned cartnum, const QString &title) { QString str; QString username; if(type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } RDPanelButton *button= panel_arrays.value(username).at(panel)->panelButton(row,col); if(button->isActive()) { return; } button->clear(); if(cartnum>0) { button->setCart(cartnum); RDCart *cart=new RDCart(cartnum); if(cart->exists()) { if(title.isEmpty()) { button-> setText(RDLogLine::resolveWildcards(cartnum,panel_label_template)); } else { button->setText(title); } button->setLength(false,cart->forcedLength()); if(cart->averageHookLength()>0) { button->setLength(true,cart->averageHookLength()); } else { button->setLength(true,cart->forcedLength()); } button->setHookMode(panel_playmode_box->currentIndex()==1); switch(cart->type()) { case RDCart::Audio: if(button->length(button->hookMode())==0) { button->setActiveLength(-1); } else { button->setActiveLength(button->length(button->hookMode())); } break; case RDCart::Macro: button->setActiveLength(cart->forcedLength()); break; case RDCart::All: break; } } else { if(title.isEmpty()) { str=QString(tr("Cart")); button->setText(str+QString::asprintf(" %06u",cartnum)); } else { button->setText(title); } } delete cart; } SaveButton(type,panel,row,col); } void RDSoundPanel::acceptCartDrop(int row,int col,unsigned cartnum, const QColor &color,const QString &title) { setButton(panel_type,panel_number,row,col,cartnum,title); if(color.isValid()&&(color.name()!="#000000")) { setColor(panel_type,panel_number,row,col,color); } } void RDSoundPanel::changeUser() { panel_config_panels=rda->user()->configPanels(); UpdatePanels(rda->user()->name()); if(panel_dump_panel_updates) { printf("%s\n",json(rda->user()->name()).constData()); // printf("{\r\n%s}\r\n",json(4).toUtf8().constData()); } // // Remove Old Panel Names // int current_item=panel_selector_box->currentIndex(); for(int i=0;iremoveItem(panel_station_panels); } // // Load New Panel Names // QString sql; sql=QString("select ")+ "`PANEL_NO`,"+ "`NAME` "+ "from "+panel_name_tablename+" where "+ QString::asprintf("(`TYPE`=%d)&&",RDAirPlayConf::UserPanel)+ "(`OWNER`='"+RDEscapeString(rda->user()->name())+"') "+ "order by `PANEL_NO`"; RDSqlQuery *q=new RDSqlQuery(sql); q->first(); for(int i=0;iisValid()&&(q->value(0).toInt()==i)) { panel_selector_box-> insertItem(QString::asprintf("[U:%d] ",i+1)+q->value(1).toString()); q->next(); } else { panel_selector_box-> insertItem(QString::asprintf("[U:%d] Panel U:%d",i+1,i+1)); } } delete q; panel_selector_box->setCurrentIndex(current_item); panelActivatedData(panel_selector_box->currentIndex()); } void RDSoundPanel::tickClock() { emit tick(); if(panel_flash) { if(panel_flash_count++>1) { emit buttonFlash(panel_flash_state); panel_flash_state=!panel_flash_state; panel_flash_count=0; } } } void RDSoundPanel::panelUp() { int index=panel_selector_box->currentIndex(); if(index<(panel_selector_box->count()-1)) { panelActivatedData(index+1); panel_selector_box->setCurrentIndex(index+1); } } void RDSoundPanel::panelDown() { int index=panel_selector_box->currentIndex(); if(index>0) { panelActivatedData(index-1); panel_selector_box->setCurrentIndex(index-1); } } void RDSoundPanel::panelActivatedData(int n) { QString username; if(panel_type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } if(nuser()->name(); } ShowPanel(panel_type,panel_number); } void RDSoundPanel::resetClickedData() { if(panel_reset_mode) { panel_reset_mode=false; panel_reset_button->setFlashingEnabled(false); panel_all_button->hide(); panel_setup_button->show(); } else { panel_reset_mode=true; panel_reset_button->setFlashingEnabled(true); panel_setup_button->hide(); panel_all_button->show(); } } void RDSoundPanel::allClickedData() { StopButton(panel_type,panel_number,-1,-1); } void RDSoundPanel::playmodeActivatedData(int n) { ShowPanel(panel_type,panel_number); } void RDSoundPanel::setupClickedData() { QString username; if(panel_type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } if(panel_setup_mode) { panel_setup_mode=false; panel_setup_button->setFlashingEnabled(false); panel_reset_button->setEnabled(true); panel_playmode_box->setEnabled(true); } else { panel_setup_mode=true; panel_setup_button->setFlashingEnabled(true); panel_reset_button->setDisabled(true); panel_playmode_box->setDisabled(true); } if(rda->station()->enableDragdrop()&&(rda->station()->enforcePanelSetup())) { for(QMap >::const_iterator it= panel_arrays.begin();it!=panel_arrays.end();it++) { for(int i=0;isetAcceptDrops(panel_setup_mode); } } } panel_selector_box->setSetupMode(panel_setup_mode); } void RDSoundPanel::buttonClickedData(int pnum,int col,int row) { if(panel_current_panel==NULL) { printf("NO CURRENT PANEL!\n"); return; } RDPanelButton *button=panel_current_panel->panelButton(row,col); unsigned cartnum; switch(panel_action_mode) { case RDAirPlayConf::CopyFrom: if((cartnum=button->cart())>0) { emit selectClicked(cartnum,0,0); } break; case RDAirPlayConf::CopyTo: if(button->playDeck()==NULL && ((panel_type==RDAirPlayConf::UserPanel) || panel_config_panels)) { emit selectClicked(0,button->row(),button->column()); } break; case RDAirPlayConf::AddTo: if(button->playDeck()==NULL && ((panel_type==RDAirPlayConf::UserPanel) || panel_config_panels)) { emit selectClicked(0,button->row(),button->column()); } break; case RDAirPlayConf::DeleteFrom: if(button->playDeck()==NULL && ((panel_type==RDAirPlayConf::UserPanel) || panel_config_panels)) { emit selectClicked(0,button->row(),button->column()); } break; default: if(panel_setup_mode) { if(button->isActive()) { return; } if((panel_type==RDAirPlayConf::StationPanel)&& (!panel_config_panels)) { ClearReset(); return; } if(panel_button_dialog-> exec(button,panel_playmode_box->currentIndex()==1, rda->user()->name(),rda->user()->password())) { SaveButton(panel_type,panel_number,button->row(),button->column()); } } else { RDPlayDeck *deck=button->playDeck(); if(panel_reset_mode) { StopButton(panel_type,panel_number,button->row(),button->column()); } else { if(deck==NULL) { PlayButton(panel_type,panel_number,button->row(),button->column(), RDLogLine::StartManual, panel_playmode_box->currentIndex()==1); } else { if(panel_pause_enabled) { if(deck->state()!=RDPlayDeck::Paused) { PauseButton(panel_type,panel_number,button->row(),button->column()); } else { PlayButton(panel_type,panel_number,button->row(),button->column(), RDLogLine::StartManual,button->hookMode()); } } else { StopButton(panel_type,panel_number,button->row(),button->column()); } } } } } ClearReset(); } void RDSoundPanel::stateChangedData(int id,RDPlayDeck::State state) { switch(state) { case RDPlayDeck::Playing: Playing(id); break; case RDPlayDeck::Stopped: case RDPlayDeck::Finished: Stopped(id); break; case RDPlayDeck::Paused: Paused(id); break; default: break; } } void RDSoundPanel::hookEndData(int id) { RDPanelButton *button=panel_active_buttons[id]; if(!button->hookMode()) { return; } RDPlayDeck *deck=button->playDeck(); if(deck!=NULL) { switch(deck->state()) { case RDPlayDeck::Playing: case RDPlayDeck::Paused: StopButton(id); break; default: break; } } } void RDSoundPanel::timescalingSupportedData(int card,bool state) { for(unsigned i=0;iuser()->configPanels()||(panel_type==RDAirPlayConf::UserPanel)) { QString sql; int cutpt=panel_selector_box->currentText().indexOf(" "); if(panel_selector_box->currentText().left(5)==tr("Panel")) { cutpt=-1; } QString tag=panel_selector_box->currentText().left(cutpt); QString panel_name=panel_selector_box->currentText(). right(panel_selector_box->currentText().length()-cutpt-1); RDEditPanelName *edn=new RDEditPanelName(&panel_name); if(edn->exec()) { panel_selector_box-> setItemText(panel_selector_box->currentIndex(),tag+" "+panel_name); panel_selector_box-> setCurrentIndex(panel_selector_box-> findText("["+PanelTag(panel_selector_box-> currentIndex())+"] "+panel_name)); sql=QString("delete from ")+panel_name_tablename+" where "+ QString::asprintf("(`TYPE`=%d)&&",panel_type)+ "(`OWNER`='"+RDEscapeString(PanelOwner(panel_type))+"')&&"+ QString::asprintf("(`PANEL_NO`=%d)",panel_number); RDSqlQuery::apply(sql); sql=QString("insert into ")+panel_name_tablename+" set "+ QString::asprintf("`TYPE`=%d,",panel_type)+ "`OWNER`='"+RDEscapeString(PanelOwner(panel_type))+"',"+ QString::asprintf("`PANEL_NO`=%d,",panel_number)+ "`NAME`='"+RDEscapeString(panel_name)+"'"; RDSqlQuery::apply(sql); } delete edn; } } void RDSoundPanel::onairFlagChangedData(bool state) { panel_onair_flag=state; } void RDSoundPanel::notificationReceivedData(RDNotification *notify) { printf("notificationReceivedData()\n"); RDPanelButton *button=NULL; QString sql; RDSqlQuery *q=NULL; if(((notify->type()==RDNotification::PanelButtonType)&& (panel_tablename=="`PANELS`"))|| ((notify->type()==RDNotification::ExtendedPanelButtonType)&& (panel_tablename=="`EXTENDED_PANELS`"))) { sql=ButtonSqlFields()+ " where "+ panel_tablename+QString::asprintf(".`ID`=%d",notify->id().toInt()); q=new RDSqlQuery(sql); if(q->first()) { RDAirPlayConf::PanelType ptype= (RDAirPlayConf::PanelType)q->value(2).toInt(); if((q->value(2).toString()==rda->station()->name())&& (ptype==RDAirPlayConf::StationPanel)) { if(panel_arrays.value("").size()>q->value(3).toInt()) { if((button=panel_arrays.value("").at(q->value(3).toInt())-> panelButton(q->value(4).toInt(),q->value(5).toInt()))!=NULL) { if(!button->isActive()) { ApplyButtonFields(button,q); } } } } if((ptype==RDAirPlayConf::UserPanel)&& (panel_arrays.contains(q->value(2).toString()))) { if(panel_arrays.value(q->value(2).toString()).size()> q->value(3).toInt()) { if((button=panel_arrays.value(q->value(2).toString()). at(q->value(3).toInt())->panelButton(q->value(4).toInt(),q->value(5).toInt()))!=NULL) { if(!button->isActive()) { ApplyButtonFields(button,q); } } } } } else { rda->syslog(LOG_WARNING, "received update for non-existent panel button [id: %d]", notify->id().toInt()); } delete q; } } void RDSoundPanel::resizeEvent(QResizeEvent *e) { // int w=size().width(); int h=size().height(); for(QMap >::const_iterator it=panel_arrays.begin();it!=panel_arrays.end();it++) { for(int i=0;isetGeometry(0,0,size().width()-5,size().height()-60); } } panel_selector_box->setGeometry(0,h-50,2*PANEL_BUTTON_SIZE_X+10,50); panel_playmode_box->setGeometry(2*PANEL_BUTTON_SIZE_X+15,h-50, PANEL_BUTTON_SIZE_X+10,50); panel_reset_button->setGeometry(2*PANEL_BUTTON_SIZE_X+140,h-50, PANEL_BUTTON_SIZE_X,50); panel_all_button->setGeometry(2*PANEL_BUTTON_SIZE_X+235,h-50, PANEL_BUTTON_SIZE_X,50); panel_setup_button->setGeometry(2*PANEL_BUTTON_SIZE_X+235,h-50, PANEL_BUTTON_SIZE_X,50); } void RDSoundPanel::wheelEvent(QWheelEvent *e) { if(e->orientation()==Qt::Vertical) { if(e->delta()>0) { panelDown(); } if(e->delta()<0) { panelUp(); } } e->accept(); } void RDSoundPanel::PlayButton(RDAirPlayConf::PanelType type,int panel, int row,int col,RDLogLine::StartSource src,bool hookmode, int mport,bool pause_when_finished) { int edit_row=row; int edit_col=col; QString username; if(type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } for(int i=0;ipanelButton(j,i)->cart()>0 && panel_arrays.value(username).at(panel)-> panelButton(j,i)->state()==false) { if(edit_col==-1 || col==i) { edit_col=i; if(edit_row==-1) { edit_row=j; } } } } } if(edit_row==-1 || edit_col==-1) { return; } RDPanelButton *button= panel_arrays.value(username).at(panel)->panelButton(edit_row,edit_col); RDPlayDeck *deck=button->playDeck(); if(deck!=NULL) { deck->play(deck->currentPosition()); if(button->hookMode()) { button->setStartTime(QTime::currentTime(). addMSecs(rda->station()->timeOffset()). addMSecs(-deck->currentPosition()+ deck->cut()->hookStartPoint())); } else { button->setStartTime(QTime::currentTime(). addMSecs(rda->station()->timeOffset()). addMSecs(-deck->currentPosition())); } return; } int cartnum=0; if((cartnum=button->cart())==0) { LogLine(QString::asprintf("Tried to start empty button. Row=%d, Col=%d", edit_row,edit_col)); return; } RDCart *cart=new RDCart(cartnum); if(!cart->exists()) { delete cart; LogLine(QString::asprintf("Tried to start non-existent cart: %u",cartnum)); return; } button->setStartSource(src); if(panel_pause_enabled) { button->setPauseWhenFinished(pause_when_finished); } else { button->setPauseWhenFinished(false); } switch(cart->type()) { case RDCart::Audio: PlayAudio(button,cart,hookmode,mport); break; case RDCart::Macro: PlayMacro(button,cart); break; default: break; } delete cart; } bool RDSoundPanel::PlayAudio(RDPanelButton *button,RDCart *cart,bool hookmode,int mport) { RDLogLine logline; bool timescale=false; int button_deck=GetFreeButtonDeck(); if(button_deck<0) { LogLine(QString(). sprintf("No button deck available, playout aborted. Cart=%u", cart->number())); return false; } if(mport<=0 || mport>RD_SOUNDPANEL_MAX_OUTPUTS) { button->setOutput(GetFreeOutput()); } else { button->setOutput(mport-1); } button->setOutputText(panel_output_text[button->output()]); button->setHookMode(hookmode); button->setPlayDeck(new RDPlayDeck(rda->cae(),button_deck,this)); button->playDeck()->setCard(panel_card[button->output()]); button->playDeck()->setPort(panel_port[button->output()]); button->playDeck()->duckVolume(button->duckVolume(),0); if(panel_timescaling_supported[panel_card[button->output()]]&& cart->enforceLength()) { timescale=true; } logline.loadCart(cart->number(),RDLogLine::Play,0,timescale); if(!button->playDeck()->setCart(&logline,true)) { delete button->playDeck(); button->setPlayDeck(NULL); LogLine(QString(). sprintf("No CAE stream available, playout aborted. Cart=%u", cart->number())); return false; } button->setCutName(logline.cutName()); panel_active_buttons[button_deck]=button; // // Set Mappings // connect(button->playDeck(),SIGNAL(stateChanged(int,RDPlayDeck::State)), this,SLOT(stateChangedData(int,RDPlayDeck::State))); connect(button->playDeck(),SIGNAL(hookEnd(int)), this,SLOT(hookEndData(int))); connect(this,SIGNAL(tick()),button,SLOT(tickClock())); // // Calculate Start Parameters for Hook Playout // int start_pos=0; int segue_start=-1; int segue_end=-1; if(hookmode&&(logline.hookStartPoint()>=0)&&(logline.hookEndPoint()>=0)) { start_pos=logline.hookStartPoint()-logline.startPoint(); segue_start=logline.hookEndPoint()-logline.startPoint(); segue_end=logline.hookEndPoint()-logline.startPoint(); } // // Start Playout // button-> setStartTime(QTime::currentTime().addMSecs(rda->station()->timeOffset())); if(hookmode&&(button->playDeck()->cut()->hookStartPoint()>=0)) { button->setActiveLength(button->playDeck()->cut()->hookEndPoint()- button->playDeck()->cut()->hookStartPoint()); } else { if(timescale) { button->setActiveLength(cart->forcedLength()); } else { button->setActiveLength(button->playDeck()->cut()->length()); } } button->playDeck()->play(start_pos,segue_start,segue_end); panel_event_player-> exec(logline.resolveWildcards(panel_start_rml[button->output()])); emit channelStarted(button->output(),button->playDeck()->card(), button->playDeck()->port()); return true; } void RDSoundPanel::PlayMacro(RDPanelButton *button,RDCart *cart) { RDMacro rml; rml.setRole(RDMacro::Cmd); rml.setAddress(rda->station()->address()); rml.setEchoRequested(false); rml.setCommand(RDMacro::EX); rml.addArg(cart->number()); rda->ripc()->sendRml(&rml); if(!panel_svcname.isEmpty()) { LogTrafficMacro(button); } if(button->pauseWhenFinished() && panel_pause_enabled) { button->setState(true); button->resetCounter(); button->setColor(RDPANEL_PAUSED_BACKGROUND_COLOR); } } void RDSoundPanel::PauseButton(RDAirPlayConf::PanelType type,int panel, int row,int col,int mport) { QString username; if(type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } for(int i=0;ipanelButton(j,i)->playDeck(); if(deck!=NULL && (row==j || row==-1) && (col==i || col==-1)) { if(mport==-1 || mport==panel_arrays.value(username).at(panel)-> panelButton(j,i)->outputText().toInt()) { deck->pause(); panel_arrays.value(username).at(panel)-> panelButton(j,i)->setStartTime(QTime()); } } } } } void RDSoundPanel::StopButton(RDAirPlayConf::PanelType type,int panel, int row,int col,int mport, bool pause_when_finished,int fade_out) { QString username; if(type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } int edit_mport=mport; if (edit_mport==0) { edit_mport=-1; } for(int i=0;i panelButton(j,i)->playDeck(); if((row==j || row==-1) && (col==i || col==-1)) { if(deck!=NULL) { if(edit_mport==-1 || edit_mport==panel_arrays.value(username). at(panel)->panelButton(j,i)->outputText().toInt()) { if(panel_pause_enabled) { panel_arrays.value(username).at(panel)-> panelButton(j,i)->setPauseWhenFinished(pause_when_finished); } else { panel_arrays.value(username).at(panel)-> panelButton(j,i)->setPauseWhenFinished(false); } switch(deck->state()) { case RDPlayDeck::Playing: deck->stop(fade_out,RD_FADE_DEPTH); break; case RDPlayDeck::Paused: deck->clear(); break; default: deck->clear(); break; } } } else { if(!pause_when_finished && panel_pause_enabled) { panel_arrays.value(username).at(panel)-> panelButton(j,i)->setState(false); panel_arrays.value(username).at(panel)-> panelButton(j,i)->setPauseWhenFinished(false); panel_arrays.value(username).at(panel)->panelButton(j,i)->reset(); } } } } } panel_reset_mode=false; panel_reset_button->setFlashingEnabled(false); panel_all_button->hide(); panel_setup_button->show(); } void RDSoundPanel::StopButton(int id) { RDPlayDeck *deck=panel_active_buttons[id]->playDeck(); StopButton(deck); } void RDSoundPanel::StopButton(RDPlayDeck *deck) { if(deck!=NULL) { switch(deck->state()) { case RDPlayDeck::Playing: deck->stop(); break; case RDPlayDeck::Paused: deck->clear(); break; default: break; } } } void RDSoundPanel::UpdatePanels(const QString &username) { QString owner=username; RDAirPlayConf::PanelType type=RDAirPlayConf::UserPanel; int max_panels=panel_user_panels; if(username.isEmpty()) { owner=rda->station()->name(); type=RDAirPlayConf::StationPanel; max_panels=panel_station_panels; } // // Load the array if it isn't already loaded // if(max_panels>0) { QList list; if(panel_arrays.value(username).size()>0) { list=panel_arrays.value(username); } for(int i=panel_arrays.value(username).size();isetGeometry(0,0,size().width()-5,size().height()-60); connect(panel,SIGNAL(buttonClicked(int,int,int)), this,SLOT(buttonClickedData(int,int,int))); panel->hide(); list.push_back(panel); } panel_arrays[username]=list; } // // Update button attributes // QString sql=ButtonSqlFields()+ "where "+panel_tablename+QString::asprintf(".`TYPE`=%d && ",type)+ panel_tablename+".`OWNER`='"+RDEscapeString(owner)+"' && "+ panel_tablename+QString::asprintf(".`PANEL_NO`<%d ",max_panels)+ "order by "+ panel_tablename+".`PANEL_NO`,"+ panel_tablename+".`COLUMN_NO`,"+ panel_tablename+".`ROW_NO`"; RDSqlQuery *q=new RDSqlQuery(sql); while(q->next()) { RDPanelButton *button=panel_arrays.value(username).at(q->value(3).toInt())-> panelButton(q->value(4).toInt(),q->value(5).toInt()); if(!button->isActive()) { ApplyButtonFields(button,q); } } delete q; } void RDSoundPanel::ShowPanel(RDAirPlayConf::PanelType type,int offset) { QString username; if(type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } if(panel_arrays.value(username).size()>offset) { if(panel_current_panel!=NULL) { panel_current_panel->hide(); } panel_arrays.value(username).at(offset)->show(); panel_current_panel=panel_arrays.value(username).at(offset); } } void RDSoundPanel::SaveButton(RDAirPlayConf::PanelType type, int panel,int row,int col) { QString sql; QString sql1; RDSqlQuery *q; QString owner; QString username; RDNotification *notify=NULL; if(type==RDAirPlayConf::UserPanel) { username=rda->user()->name(); } switch(type) { case RDAirPlayConf::UserPanel: owner=rda->user()->name(); break; case RDAirPlayConf::StationPanel: owner=rda->station()->name(); break; } RDPanelButton *button= panel_arrays.value(username).at(panel)->panelButton(row,col); // // Determine if the button exists // sql=QString("select ")+ "`ID` "+ // 00 "from "+panel_tablename+" where "+ QString::asprintf("`TYPE`=%d && ",type)+ "`OWNER`='"+RDEscapeString(owner)+"' && "+ QString::asprintf("`PANEL_NO`=%d && ",panel)+ QString::asprintf("`ROW_NO`=%d && ",row)+ QString::asprintf("`COLUMN_NO`=%d",col); q=new RDSqlQuery(sql); if(q->first()) { // // If so, update the record // sql1=QString("update ")+panel_tablename+" set "+ "`LABEL`='"+RDEscapeString(button->text())+"',"+ QString::asprintf("`CART`=%d,",button->cart())+ "`DEFAULT_COLOR`='"+button->defaultColor().name()+"' where "+ QString::asprintf("`ID`=%d",q->value(0).toInt()); RDSqlQuery::apply(sql1); if(panel_tablename=="`PANELS`") { notify=new RDNotification(RDNotification::PanelButtonType, RDNotification::ModifyAction, q->value(0).toInt()); } else { notify=new RDNotification(RDNotification::ExtendedPanelButtonType, RDNotification::ModifyAction, q->value(0).toInt()); } } else { // // Otherwise, insert a new one // sql1=QString("insert into ")+panel_tablename+ " (`TYPE`,"+ "`OWNER`,"+ "`PANEL_NO`,"+ "`ROW_NO`,"+ "`COLUMN_NO`,"+ "`LABEL`,"+ "`CART`,"+ "`DEFAULT_COLOR`) "+ QString::asprintf("values (%d,",type)+ "'"+RDEscapeString(owner)+"',"+ QString::asprintf("%d,%d,%d,",panel,row,col)+ "'"+RDEscapeString(button->text())+"',"+ QString::asprintf("%d,",button->cart())+ "'"+RDEscapeString(button->defaultColor().name())+"')"; int new_id=RDSqlQuery::run(sql1).toInt(); if(panel_tablename=="`PANELS`") { notify=new RDNotification(RDNotification::PanelButtonType, RDNotification::AddAction, new_id); } else { notify=new RDNotification(RDNotification::ExtendedPanelButtonType, RDNotification::AddAction, new_id); } } rda->ripc()->sendNotification(*notify); delete notify; delete q; } int RDSoundPanel::GetFreeButtonDeck() { for(int i=0;ioutput()==i)) { active=true; } } if(!active) { return i; } } return RD_SOUNDPANEL_MAX_OUTPUTS-1; } void RDSoundPanel::LogPlayEvent(unsigned cartnum,int cutnum) { RDCut *cut=new RDCut(QString::asprintf("%06u_%03d",cartnum,cutnum)); cut->logPlayout(); delete cut; } void RDSoundPanel::LogTraffic(RDPanelButton *button) { if(panel_svcname.isEmpty()) { return; } QString sql; RDSqlQuery *q; QDateTime now=QDateTime::currentDateTime(); sql=QString("select ")+ "`CART`.`TITLE`,"+ // 00 "`CART`.`ARTIST`,"+ // 01 "`CART`.`PUBLISHER`,"+ // 02 "`CART`.`COMPOSER`,"+ // 03 "`CART`.`USAGE_CODE`,"+ // 04 "`CUTS`.`ISRC`,"+ // 05 "`CART`.`ALBUM`,"+ // 06 "`CART`.`LABEL`,"+ // 07 "`CUTS`.`ISCI`,"+ // 08 "`CART`.`CONDUCTOR`,"+ // 09 "`CART`.`USER_DEFINED`,"+ // 10 "`CART`.`SONG_ID`,"+ // 11 "`CUTS`.`DESCRIPTION`,"+ // 12 "`CUTS`.`OUTCUE` "+ // 13 "from `CART` left join `CUTS` "+ "on `CART`.`NUMBER`=`CUTS`.`CART_NUMBER` where "+ "`CUTS`.`CUT_NAME`='"+RDEscapeString(button->cutName())+"'"; q=new RDSqlQuery(sql); if(q->first()) { sql=QString("insert into `ELR_LINES` set ")+ "`SERVICE_NAME`='"+RDEscapeString(panel_svcname)+"',"+ QString::asprintf("`LENGTH`=%d,",button->startTime().msecsTo(now.time()))+ QString::asprintf("`CART_NUMBER`=%u,",button->cart())+ "`STATION_NAME`='"+RDEscapeString(rda->station()->name().toUtf8())+"',"+ "`EVENT_DATETIME`="+ RDCheckDateTime(QDateTime(now.date(),button->startTime()), "yyyy-MM-dd hh:mm:ss")+","+ QString::asprintf("`EVENT_TYPE`=%d,",RDAirPlayConf::TrafficStop)+ QString::asprintf("`EVENT_SOURCE`=%d,",RDLogLine::SoundPanel)+ QString::asprintf("`PLAY_SOURCE`=%d,",RDLogLine::SoundPanel)+ QString::asprintf("`CUT_NUMBER`=%d,",button->cutName().right(3).toInt())+ "`TITLE`='"+RDEscapeString(q->value(0).toString().toUtf8())+"',"+ "`ARTIST`='"+RDEscapeString(q->value(1).toString().toUtf8())+"',"+ "`PUBLISHER`='"+RDEscapeString(q->value(2).toString().toUtf8())+"',"+ "`COMPOSER`='"+RDEscapeString(q->value(3).toString().toUtf8())+"',"+ QString::asprintf("`USAGE_CODE`=%d,",q->value(4).toInt())+ "`ISRC`='"+RDEscapeString(q->value(5).toString().toUtf8())+"',"+ QString::asprintf("`START_SOURCE`=%d,",button->startSource())+ "`ALBUM`='"+RDEscapeString(q->value(6).toString().toUtf8())+"',"+ "`LABEL`='"+RDEscapeString(q->value(7).toString().toUtf8())+"',"+ "`ISCI`='"+RDEscapeString(q->value(8).toString().toUtf8())+"',"+ "`DESCRIPTION`='"+RDEscapeString(q->value(12).toString().toUtf8())+"',"+ "`OUTCUE`='"+RDEscapeString(q->value(13).toString().toUtf8())+"',"+ "`CONDUCTOR`='"+RDEscapeString(q->value(9).toString().toUtf8())+"',"+ "`USER_DEFINED`='"+RDEscapeString(q->value(10).toString().toUtf8())+"',"+ "`SONG_ID`='"+RDEscapeString(q->value(11).toString().toUtf8())+"',"+ "`ONAIR_FLAG`='"+RDYesNo(panel_onair_flag)+"'"; RDSqlQuery::apply(sql); } delete q; } void RDSoundPanel::LogTrafficMacro(RDPanelButton *button) { QString sql; RDSqlQuery *q; QDateTime datetime(QDate::currentDate(),QTime::currentTime()); sql=QString("select ")+ "`TITLE`,"+ // 00 "`ARTIST`,"+ // 01 "`PUBLISHER`,"+ // 02 "`COMPOSER`,"+ // 03 "`USAGE_CODE`,"+ // 04 "`FORCED_LENGTH`,"+ // 05 "`ALBUM`,"+ // 06 "`LABEL` "+ // 07 "from `CART` where "+ QString::asprintf("`NUMBER`=%u",button->cart()); q=new RDSqlQuery(sql); if(q->first()) { sql=QString("insert into `ELR_LINES` set ")+ "`SERVICE_NAME`='"+RDEscapeString(panel_svcname)+"',"+ QString::asprintf("`LENGTH`=%d,",q->value(5).toUInt())+ QString::asprintf("`CART_NUMBER`=%u,",button->cart())+ "`STATION_NAME`='"+RDEscapeString(rda->station()->name().toUtf8())+"',"+ "`EVENT_DATETIME`='"+datetime.toString("yyyy-MM-dd hh:mm:ss")+"',"+ QString::asprintf("`EVENT_TYPE`=%d,",RDAirPlayConf::TrafficMacro)+ QString::asprintf("`EVENT_SOURCE`=%d,",RDLogLine::SoundPanel)+ QString::asprintf("`PLAY_SOURCE`=%d,",RDLogLine::SoundPanel)+ "`TITLE`='"+RDEscapeString(q->value(0).toString().toUtf8())+"',"+ "`ARTIST`='"+RDEscapeString(q->value(1).toString().toUtf8())+"',"+ "`PUBLISHER`='"+RDEscapeString(q->value(2).toString().toUtf8())+"',"+ "`COMPOSER`='"+RDEscapeString(q->value(3).toString().toUtf8())+"',"+ QString::asprintf("`USAGE_CODE`=%d,",q->value(4).toInt())+ QString::asprintf("`START_SOURCE`=%d,",button->startSource())+ "`ALBUM`='"+RDEscapeString(q->value(6).toString().toUtf8())+"',"+ "`LABEL`='"+RDEscapeString(q->value(7).toString().toUtf8())+"',"+ "`ONAIR_FLAG`='"+RDYesNo(panel_onair_flag)+"'"; delete q; RDSqlQuery::apply(sql); } } void RDSoundPanel::LogLine(QString str) { FILE *file; if(panel_logfile.isEmpty()) { return; } QDateTime current=QDateTime::currentDateTime(); if((file=fopen(panel_logfile.toUtf8(),"a"))==NULL) { return; } fprintf(file,"%02d/%02d/%4d - %02d:%02d:%02d.%03d : RDSoundPanel: %s\n", current.date().month(), current.date().day(), current.date().year(), current.time().hour(), current.time().minute(), current.time().second(), current.time().msec(), str.toUtf8().constData()); fclose(file); } void RDSoundPanel::Playing(int id) { if(panel_active_buttons[id]==NULL) { LogLine(QString::asprintf("Invalid ID=%d in RDSoundPanel::Playing()", id)); return; } panel_active_buttons[id]->setState(true); panel_active_buttons[id]->setColor(RDPANEL_PLAY_BACKGROUND_COLOR); LogPlayEvent(panel_active_buttons[id]->playDeck()->cart()->number(), panel_active_buttons[id]->playDeck()->cut()->cutNumber()); LogLine(QString(). sprintf("Playout started: id=%d cart=%u cut=%d", id,panel_active_buttons[id]->playDeck()->cart()->number(), panel_active_buttons[id]->playDeck()->cut()->cutNumber())); } void RDSoundPanel::Paused(int id) { if(panel_active_buttons[id]==NULL) { LogLine(QString::asprintf("Invalid ID=%d in RDSoundPanel::Paused()", id)); return; } panel_active_buttons[id]->setState(true); panel_active_buttons[id]->setColor(RDPANEL_PAUSED_BACKGROUND_COLOR); LogLine(QString(). sprintf("Playout paused: id=%d cart=%u cut=%d", id,panel_active_buttons[id]->playDeck()->cart()->number(), panel_active_buttons[id]->playDeck()->cut()->cutNumber())); } void RDSoundPanel::Stopped(int id) { RDPanelButton *button=panel_active_buttons[id]; if(button==NULL) { LogLine(QString::asprintf("Invalid ID=%d in RDSoundPanel::Stopped()", id)); return; } LogTraffic(button); ClearChannel(id); if(button->pauseWhenFinished()) { button->setState(true); button->setColor(RDPANEL_PAUSED_BACKGROUND_COLOR); button->resetCounter(); } else { button->setState(false); button->setHookMode(panel_playmode_box->currentIndex()==1); } disconnect(this,SIGNAL(tick()),button,SLOT(tickClock())); button->playDeck()->disconnect(); delete button->playDeck(); button->setPlayDeck(NULL); if(!button->pauseWhenFinished()) { button->reset(); } button->setDuckVolume(0); panel_active_buttons[id]=NULL; UpdateButton(button); LogLine(QString::asprintf("Playout stopped: id=%d",id)); } void RDSoundPanel::ClearChannel(int id) { RDPlayDeck *playdeck=panel_active_buttons[id]->playDeck(); if(rda->cae()-> playPortStatus(playdeck->card(),playdeck->port(),playdeck->serial())) { return; } panel_event_player->exec(panel_stop_rml[panel_active_buttons[id]->output()]); emit channelStopped(panel_active_buttons[id]->output(), playdeck->card(),playdeck->port()); } void RDSoundPanel::ClearReset() { panel_reset_mode=false; panel_reset_button->setFlashingEnabled(false); panel_setup_button->setEnabled(true); } QString RDSoundPanel::PanelTag(int index) { if(indexstation()->name(); case RDAirPlayConf::UserPanel: return rda->user()->name(); } return QString(); } QString RDSoundPanel::PanelName(RDAirPlayConf::PanelType type,int panel_num) { QString ret; QString sql=QString("select ")+ "`NAME` "+ // 00 "from "+panel_name_tablename+" where "+ QString::asprintf("`TYPE`=%u && ",type)+ QString::asprintf("`PANEL_NO`=%d ",panel_num); switch(type) { case RDAirPlayConf::StationPanel: sql+="&& `OWNER`='"+RDEscapeString(rda->station()->name())+"' "; break; case RDAirPlayConf::UserPanel: sql+="&& `OWNER`='"+RDEscapeString(rda->user()->name())+"' "; break; } RDSqlQuery *q=new RDSqlQuery(sql); if(q->first()) { ret=q->value(0).toString(); } delete q; return ret; } RDPanelButton *RDSoundPanel::GetVisibleButton(int row,int col) const { return NULL; } QString RDSoundPanel::ButtonSqlFields() const { QString sql=QString("select ")+ panel_tablename+".`ID`,"+ // 00 panel_tablename+".`TYPE`,"+ // 01 panel_tablename+".`OWNER`,"+ // 02 panel_tablename+".`PANEL_NO`,"+ // 03 panel_tablename+".`ROW_NO`,"+ // 04 panel_tablename+".`COLUMN_NO`,"+ // 05 panel_tablename+".`LABEL`,"+ // 06 panel_tablename+".`CART`,"+ // 07 panel_tablename+".`DEFAULT_COLOR`,"+ // 08 "`CART`.`FORCED_LENGTH`,"+ // 09 "`CART`.`AVERAGE_HOOK_LENGTH`,"+ // 10 "`CART`.`TYPE` "+ // 11 "from "+panel_tablename+" "+ "left join `CART` on "+panel_tablename+".`CART`=`CART`.`NUMBER` "; return sql; } void RDSoundPanel::ApplyButtonFields(RDPanelButton *button,RDSqlQuery *q) { button->setDbId(q->value(0).toInt()); button->setText(q->value(6).toString()); button->setCart(q->value(7).toInt()); button->setLength(false,q->value(9).toInt()); button->setLength(true,q->value(10).toInt()); if((panel_playmode_box!=NULL)&&(panel_playmode_box->currentIndex()==1)&& (q->value(10).toUInt()>0)) { button->setActiveLength(q->value(10).toInt()); } else { if(q->value(11).toInt()==RDCart::Macro) { button->setActiveLength(q->value(8).toInt()); } else { if(q->value(9).toInt()>0) { button->setActiveLength(q->value(9).toInt()); } else { button->setActiveLength(-1); } } } if(q->value(8).toString().isEmpty()) { button->setColor(palette().color(QPalette::Background)); button->setDefaultColor(palette().color(QPalette::Background)); } else { button->setColor(QColor(q->value(8).toString())); button->setDefaultColor(QColor(q->value(8).toString())); } } void RDSoundPanel::UpdateButton(RDPanelButton *button) { rda-> syslog(LOG_DEBUG,"updating SoundPanel button - db_id: %d",button->dbId()); QString sql=ButtonSqlFields()+"where "+ panel_tablename+QString::asprintf(".`ID`=%d",button->dbId()); RDSqlQuery *q=new RDSqlQuery(sql); if(q->first()) { button->setOutputText(""); ApplyButtonFields(button,q); } delete q; }