aboutsummaryrefslogtreecommitdiffstats
path: root/krecord.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'krecord.cpp')
-rw-r--r--krecord.cpp658
1 files changed, 658 insertions, 0 deletions
diff --git a/krecord.cpp b/krecord.cpp
new file mode 100644
index 0000000..fc31bbe
--- /dev/null
+++ b/krecord.cpp
@@ -0,0 +1,658 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <iostream>
+
+#include <qlabel.h>
+#include <qfiledialog.h>
+#include <qdragobject.h>
+#include <qtooltip.h>
+#include <qlayout.h>
+#include <qbuttongroup.h>
+#include <qhbuttongroup.h>
+#include <qradiobutton.h>
+#include <qaccel.h>
+#include <qmenubar.h>
+#include <qpopupmenu.h>
+
+#include <kapp.h>
+#include <kuniqueapp.h>
+#include <kmessagebox.h>
+#include <kmenubar.h>
+#include <kstatusbar.h>
+#include <kmainwindow.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <khelpmenu.h>
+#include <kmenubar.h>
+#include <kpopupmenu.h>
+
+#include "sound.h"
+#include "fft.h"
+#include "level.h"
+#include "buffer.h"
+#include "krecord.moc"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xmu/WinUtil.h> /* 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 <dev>", "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 <kraxel@bytesex.org>\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();
+};