#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sound.h" #include "fft.h" #include "level.h" #include "buffer.h" #include "krecord.moc" #include #include #include /* for XmuClientWindow() */ #define STAT_LATENCY 1 #define STAT_RATE 2 #define STAT_CHANNELS 3 #define STAT_FORMAT 4 #define STAT_MISC 5 KApplication *globalKapp; KIconLoader *globalKIL; KLocale *globalKlocale; const char *device = NULL; /* ------------------------------------------------------------------------ */ int main(int argc, char **argv) { static KCmdLineOptions options[] = { { "d", 0, 0 }, { "device ", "dsp sound device", "/dev/dsp" }, { "+[files]", "optional wav files", 0 }, KCmdLineLastOption }; KCmdLineArgs *args; KRecord *krecord; int i; KAboutData aboutData("krecord", "KRecord", KRECORD_VERSION, "KDE sound recorder", KAboutData::License_GPL, "(c) 1997-2003 Gerd Knorr \n", 0, "http://bytesex.org/krecord.html"); aboutData.addAuthor("Gerd Knorr","Maintainer & Developer", "kraxel@bytesex.org", "http://bytesex.org"); aboutData.addCredit("Thomas Strehl", "KDE2 port", "tstrehl@suse.de"); KCmdLineArgs::init(argc, argv, &aboutData); KCmdLineArgs::addCmdLineOptions(options); globalKapp = new KApplication("krecord"); globalKIL = KGlobal::iconLoader(); globalKlocale = KGlobal::locale(); args = KCmdLineArgs::parsedArgs(); if (args->isSet("device")) device = args->getOption("device"); krecord = new KRecord(); for (i = 0; i < args->count(); i++) { fprintf(stderr,"file: %s\n",args->arg(i)); krecord->blist->add_filebuffer(args->arg(i)); } args->clear(); return globalKapp->exec(); } /* ------------------------------------------------------------------------ */ KRecord::KRecord() : KMainWindow(0,"main") { int i = -1; soundcard = new Soundcard(device); soundopts = new SoundOptions(soundcard,"soundopts"); kfft = new KFFT(soundcard); klevel = new KLevel(soundcard); listwidget = new QListBox(this,"bufferlist"); blist = new BufferList(listwidget,soundcard); fdialog = new QFileDialog(NULL,"*.wav",NULL,"fdialog",TRUE); accel = new QAccel(this); globalKapp->setMainWidget(this); setCentralWidget(listwidget); setAcceptDrops(TRUE); create_menu(); create_toolbar(); create_soundbar(); create_statusline(); soundopts->set_soundparam(44100,2,FMT_16BIT,0); accel->connectItem(accel->insertItem(Key_Enter), blist,SLOT(play())); accel->connectItem(accel->insertItem(Key_Return), blist,SLOT(play())); accel->connectItem(accel->insertItem(Key_Escape), blist,SLOT(stop())); accel->connectItem(accel->insertItem(Key_Delete), blist,SLOT(del_buf())); accel->connectItem(accel->insertItem(Key_R), blist,SLOT(record())); accel->connectItem(accel->insertItem(Key_N), blist,SLOT(next_buffer())); accel->connectItem(accel->insertItem(Key_Space), blist,SLOT(next_buffer())); connect(soundcard,SIGNAL(newparams(struct SOUNDPARAMS*)), this, SLOT(update_statusline(struct SOUNDPARAMS*))); connect(blist,SIGNAL(status(const char*)), this, SLOT(update_statusline(const char*))); connect(soundopts,SIGNAL(set_level(int)), blist, SLOT(set_level(int))); /* session management */ if (globalKapp->isRestored()) { for (i = 1; canBeRestored(i); i++) if (0 == strcmp(classNameOfToplevel(i),"KRecord")) break; if (!canBeRestored(i)) i = -1; } if (i > 0) { restore(i); } else { resize(400,250); show(); } blist->monitor(); } KRecord::~KRecord() { delete opt_menu; delete file_menu; delete toolbar; delete soundbar; delete statusline; delete blist; delete listwidget; delete fdialog; delete kfft; delete soundopts; delete soundcard; } void KRecord::create_menu() { file_menu = new QPopupMenu; file_menu->insertItem( i18n("&New memory buffer"), blist, SLOT(new_ram())); file_menu->insertItem( i18n("New &file buffer..."), this, SLOT(new_file())); file_menu->insertItem( i18n("&Save buffer as..."), this, SLOT(save_as())); file_menu->insertSeparator(); file_menu->insertItem( i18n("&Delete buffer"), blist, SLOT(del_buf())); file_menu->insertSeparator(); file_menu->insertItem( i18n("&Quit"), this, SLOT(quit_cb()), CTRL+Key_Q); opt_menu = new QPopupMenu; opt_menu->insertItem( i18n("&Sound Options..."), this, SLOT(record_options())); opt_menu->insertItem( i18n("&Freq Spectrum..."), kfft, SLOT(showit())); opt_menu->insertItem( i18n("&Input Level..."), klevel, SLOT(showit())); opt_menu->insertItem( i18n("Run &Mixer"), this, SLOT(exec_mixer())); opt_menu->insertSeparator(); tb_mid = opt_menu->insertItem( i18n("Hide &Toolbar"), this,SLOT(tb_toggle())); sl_mid = opt_menu->insertItem( i18n("Hide Status&line"), this,SLOT(sl_toggle())); KPopupMenu *help = helpMenu(); menuBar()->insertItem( i18n("&File"), file_menu); menuBar()->insertItem( i18n("&Options"), opt_menu); menuBar()->insertItem( i18n("&Help"), help); } void KRecord::create_toolbar() { toolbar = new KToolBar(this,"Toolbar"); KIconLoader *loader = KGlobal::iconLoader(); QPixmap pixmap; pixmap = loader->loadIcon("filenew",KIcon::Toolbar); toolbar->insertButton (pixmap, 0, SIGNAL(clicked()), blist, SLOT(new_ram()), TRUE, i18n("New memory buffer")); pixmap = loader->loadIcon("filesave",KIcon::Toolbar); toolbar->insertButton (pixmap, 0, SIGNAL(clicked()), this, SLOT(save_as()), TRUE, i18n("Save buffer")); toolbar->insertSeparator(); pixmap = loader->loadIcon("freq",KIcon::Toolbar); toolbar->insertButton (pixmap, 0, SIGNAL(clicked()), kfft, SLOT(showit()), TRUE, i18n("Freq Spectrum")); pixmap = loader->loadIcon("level",KIcon::Toolbar); toolbar->insertButton (pixmap, 0, SIGNAL(clicked()), klevel, SLOT(showit()), TRUE, i18n("Input Level")); toolbar->insertSeparator(); #if 0 pixmap = loader->loadIcon("help",KIcon::Toolbar,10); toolbar->insertButton (pixmap, 0, SIGNAL(clicked()), this, SLOT(help_cb()), TRUE, i18n("Help")); #endif toolbar->insertSeparator(); pixmap = loader->loadIcon("exit",KIcon::Toolbar); toolbar->insertButton (pixmap, 0, SIGNAL(clicked()), this, SLOT(quit_cb()), TRUE, i18n("Quit")); toolbar->setBarPos(KToolBar::Top); addToolBar(toolbar); } void KRecord::create_soundbar() { soundbar = new KToolBar(this,"Soundbar"); KIconLoader *loader = KGlobal::iconLoader(); QPixmap pixmap; pixmap = loader->loadIcon("forward",KIcon::Toolbar,10); soundbar->insertButton (pixmap, 0, SIGNAL(clicked()), blist, SLOT(next_buffer()), TRUE, i18n("Switch to new buffer")); pixmap = loader->loadIcon("mrecord",KIcon::Toolbar); soundbar->insertButton (pixmap, 0, SIGNAL(clicked()), blist, SLOT(record()), TRUE, i18n("Start Record")); pixmap = loader->loadIcon("player_stop",KIcon::Toolbar); soundbar->insertButton (pixmap, 0, SIGNAL(clicked()), blist, SLOT(stop()), TRUE, i18n("Stop Record/Playback")); pixmap = loader->loadIcon("1rightarrow",KIcon::Toolbar); soundbar->insertButton (pixmap, 0, SIGNAL(clicked()), blist, SLOT(play()), TRUE, i18n("Start Playback")); pixmap = loader->loadIcon("2leftarrow",KIcon::Toolbar); soundbar->insertButton (pixmap, 0, SIGNAL(clicked()), blist, SLOT(backward()), TRUE, i18n("Back")); pixmap = loader->loadIcon("2rightarrow",KIcon::Toolbar); soundbar->insertButton (pixmap, 0, SIGNAL(clicked()), blist, SLOT(forward()), TRUE, i18n("Forward")); soundbar->insertSeparator(); pixmap = loader->loadIcon("line_monitor",KIcon::Toolbar); soundbar->insertButton (pixmap, 0, SIGNAL(clicked()), blist, SLOT(monitor()), TRUE, i18n("Turn on/off monitor")); soundbar->setBarPos(KToolBar::Top); addToolBar(soundbar); } void KRecord::create_statusline() { statusline = new KStatusBar(this); statusline->insertItem("-", STAT_MISC, 1); statusline->setItemAlignment (STAT_MISC, AlignLeft); statusline->insertFixedItem("9999999", STAT_RATE); statusline->insertFixedItem("xxxxxxx", STAT_CHANNELS); statusline->insertFixedItem("xxxxxxxxxx", STAT_FORMAT); statusline->insertFixedItem("999 ms", STAT_LATENCY); } void KRecord::update_statusline(struct SOUNDPARAMS *p) { char text[32]; statusline->changeItem((1==p->channels) ? "mono":"stereo", STAT_CHANNELS); sprintf(text,"%d",p->rate); statusline->changeItem(text,STAT_RATE); sprintf(text,"%d ms",p->latency); statusline->changeItem(text,STAT_LATENCY); statusline->changeItem(sndfmt2str(p->format),STAT_FORMAT); } void KRecord::update_statusline(const char *text) { statusline->changeItem(text,STAT_MISC); } /* ------------------------------------------------------------------------ */ void KRecord::new_file() { QString filename; if (NULL == (filename = fdialog->getSaveFileName (NULL,"*.wav",NULL,"fdialog"))) return; blist->add_filebuffer(filename); } void KRecord::save_as() { QString filename; if (NULL == (filename = fdialog->getSaveFileName (NULL,"*.wav",NULL,"fdialog"))) return; blist->save_buf(filename); } void KRecord::quit_cb() { blist->stop(); delete this; globalKapp->quit(); } void KRecord::record_options() { soundopts->show(); } void KRecord::exec_mixer() { KProcess *kmix; kmix = new KProcess; *kmix << "kmix"; kmix->start(KProcess::DontCare); } void KRecord::tb_toggle() { if (toolBar("Toolbar")->isVisible()) { toolBar("Toolbar")->enable(KToolBar::Hide); opt_menu->changeItem(i18n("Show &Toolbar"), tb_mid); } else { toolBar("Toolbar")->enable(KToolBar::Show); opt_menu->changeItem(i18n("Hide &Toolbar"), tb_mid); } } void KRecord::sl_toggle() { if (statusBar()->isVisible()) { statusBar()->hide(); opt_menu->changeItem(i18n("Show Status&line"), sl_mid); } else { statusBar()->show(); opt_menu->changeItem(i18n("Hide Status&line"), sl_mid); } } void KRecord::dropEvent(QDropEvent *de) // something has been dropped { QStrList strlist; QUriDrag::decode(de,strlist); QString *url = new QString(strlist.first()); const char *h; fprintf(stderr,"dropEvent\n"); while ((const char*)*url) { h = (const char*)*url; if (0 == strncmp(h,"file:",5)) blist->add_filebuffer(h+5); delete url; url = new QString(strlist.next()); } } void KRecord::dragEnterEvent(QDragEnterEvent* event) { event->accept(QTextDrag::canDecode(event) || QImageDrag::canDecode(event)); } /* ------------------------------------------------------------------------ */ KFFT::KFFT(Soundcard *card) : KMainWindow(0,"fft",WType_TopLevel) { int i = -1; QWidget* centralWidget = new QWidget(this); setCentralWidget(centralWidget); QVBoxLayout *topLayout = new QVBoxLayout(centralWidget,0); /* button group #1 */ QButtonGroup* linLogGroup = new QHButtonGroup( centralWidget, "LinLogGroup" ); topLayout->addWidget(linLogGroup,0); QRadioButton* rb1 = new QRadioButton( linLogGroup ); rb1->setText( i18n("L&og") ); QToolTip::add( rb1, i18n("Logarithmic Y scale") ); QRadioButton* rb2 = new QRadioButton( linLogGroup ); rb2->setText( i18n("L&inear") ); rb2->setChecked( TRUE ); QToolTip::add( rb2, i18n("Linear Y scale") ); fftwin = new FFTWindow(centralWidget,"fft"); topLayout->addWidget(fftwin,1); QObject::connect(card,SIGNAL(senddata(void*)), fftwin, SLOT(new_data(void*))); QObject::connect(card,SIGNAL(newparams(struct SOUNDPARAMS*)), fftwin, SLOT(new_params(struct SOUNDPARAMS*))); QObject::connect(linLogGroup, SIGNAL(clicked(int)), fftwin, SLOT(set_ylog(int)) ); setCaption("freq spectrum"); #if 1 /* session management */ if (globalKapp->isRestored()) { for (i = 1; canBeRestored(i); i++) if (0 == strcmp(classNameOfToplevel(i),"KFFT")) break; if (!canBeRestored(i)) i = -1; } if (i > 0) { restore(i); } else { resize(200,120); } #else resize(200,120); #endif } KFFT::~KFFT() { delete fftwin; fftwin = NULL; } void KFFT::showit() { if (!isVisible()) show(); } /* ------------------------------------------------------------------------ */ KLevel::KLevel(Soundcard *card) : KMainWindow(0,"level",WType_TopLevel) { QRadioButton *rb1; QRadioButton *rb2; thislevelwidget = new QWidget(this); setCentralWidget(thislevelwidget); QVBoxLayout *topLayout = new QVBoxLayout(thislevelwidget,0); QHBoxLayout *hbox = new QHBoxLayout(); topLayout->addLayout(hbox); /* button group #1 */ PowMaxGroup = new QButtonGroup( thislevelwidget, "PowMaxGroup" ); QHBoxLayout *vbox = new QHBoxLayout(PowMaxGroup); hbox->addWidget(PowMaxGroup); rb1 = new QRadioButton( PowMaxGroup ); rb1->setText( i18n("L&og") ); rb1->setChecked( TRUE ); vbox->addWidget(rb1); rb1->setMinimumSize(rb1->sizeHint()); QToolTip::add( rb1, i18n("Logarithmic scale") ); rb2 = new QRadioButton( PowMaxGroup ); rb2->setText( i18n("L&inear") ); vbox->addWidget(rb2); rb2->setMinimumSize( rb2->sizeHint() ); QToolTip::add( rb2, i18n("Linear scale") ); connect( PowMaxGroup, SIGNAL(clicked(int)), SLOT(LogvsLinearClicked(int))); /* button group #2 */ LogLinGroup = new QButtonGroup( thislevelwidget, "LogLinGroup" ); vbox = new QHBoxLayout(LogLinGroup, 2); hbox->addWidget( LogLinGroup, 0); rb1 = new QRadioButton( LogLinGroup ); rb1->setText( i18n("&Power") ); rb1->setChecked( TRUE ); vbox->addWidget(rb1); rb1->setMinimumSize( rb1->sizeHint() ); QToolTip::add( rb1, i18n("Display power carried by signal") ); rb2 = new QRadioButton( LogLinGroup ); rb2->setText( i18n("&Max") ); vbox->addWidget(rb2); rb2->setMinimumSize( rb2->sizeHint() ); QToolTip::add( rb2, i18n("Display signal maximum level") ); /* level window */ levelwin = new LevelWindow(thislevelwidget,"level"); levelwin->setMinimumSize(40,10); topLayout->addWidget(levelwin, 1); QObject::connect(card,SIGNAL(senddata(void*)), levelwin, SLOT(new_data(void*))); QObject::connect(card,SIGNAL(newparams(struct SOUNDPARAMS*)), levelwin, SLOT(new_params(struct SOUNDPARAMS*))); setCaption("input level"); /* scale */ hbox = new QHBoxLayout(); topLayout->addLayout(hbox); llabel = new QLabel(thislevelwidget,"llabel"); llabel->setText("-100 dB"); llabel->setAlignment(AlignLeft); llabel->setMinimumSize(llabel->sizeHint()); mlabel = new QLabel(thislevelwidget,"mlabel"); mlabel->setText("-"); mlabel->setAlignment(AlignCenter); mlabel->setMinimumSize(mlabel->sizeHint()); rlabel = new QLabel(thislevelwidget,"rlabel"); rlabel->setText("0 dB"); rlabel->setAlignment(AlignRight); rlabel->setMinimumSize(llabel->sizeHint()); hbox->addWidget(llabel,1); hbox->addWidget(mlabel,1); hbox->addWidget(rlabel,1); connect(LogLinGroup, SIGNAL(clicked(int)), SLOT(PowervsMaxClicked(int))); connect(levelwin,SIGNAL(setvalue(char*)), this,SLOT(setvalue(char*))); /* show it */ setMaximumSize(800,80); resize(320,100); topLayout->activate(); } KLevel::~KLevel() { delete thislevelwidget; thislevelwidget = NULL; delete levelwin; levelwin = NULL; } void KLevel::showit() { if (!isVisible()) show(); } void KLevel::resizeEvent( QResizeEvent * ) { thislevelwidget->resize(size()); thislevelwidget->show(); } void KLevel::setvalue(char *text) { mlabel->setText(text); } void KLevel::updatelabels() { if (levelwin->PowervsMax) { if (levelwin->LogvsLinear) { llabel->setText("-100 dB"); rlabel->setText("0 dB"); } else { llabel->setText(""); rlabel->setText(""); } } else { if (levelwin->LogvsLinear) { llabel->setText("-50 dB"); rlabel->setText("0 dB"); } else { llabel->setText("0%"); rlabel->setText("100%"); } } mlabel->setText(""); } void KLevel::PowervsMaxClicked(int i) { if (i==0) levelwin->PowervsMax=true; else levelwin->PowervsMax=false; updatelabels(); }; void KLevel::LogvsLinearClicked(int i) { if (i==0) levelwin->LogvsLinear=1; else levelwin->LogvsLinear=0; updatelabels(); };