Főoldal | Osztályhierarchia | Osztálylista | Fájllista | Osztálytagok | Fájlelemek | Kapcsolódó lapok

wavewidget.cc

00001 /*
00002  * SubTimer source file
00003  *  Copyright (C) 2005 Peter Salvi
00004  *   Last modification: <2005.03.23., 16:21:02>
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #include <qapplication.h>
00022 #include <qbrush.h>
00023 #include <qevent.h>
00024 #include <qmessagebox.h>
00025 #include <qmutex.h>
00026 #include <qpainter.h>
00027 #include <qpen.h>
00028 #include <qpixmap.h>
00029 #include <qsize.h>
00030 #include <qsizepolicy.h>
00031 #include <qstring.h>
00032 #include <qtimer.h>
00033 #include <qwidget.h>
00034 
00035 #include "common.hh"
00036 #include "oggwave.hh"
00037 #include "playthread.hh"
00038 #include "wavefile.hh"
00039 #include "wavewidget.hh"
00040 
00041 WaveWidget::WaveWidget(QWidget *parent, const char *name) 
00042   : QWidget (parent, name)
00043 {
00044   wave_file = NULL;
00045   playdata = NULL;
00046   playing = false;
00047 
00048   pthread = new PlayThread;
00049   paint_lock = new QMutex;
00050 
00051   paint_timer = new QTimer(this);
00052   connect(paint_timer, SIGNAL(timeout()), this, SLOT(repaint()));
00053   
00054   xzoom = (int)(4 * 640.0 / MAX_PIXPERSEC); yzoom = 4;
00055   setBackgroundMode(Qt::NoBackground);
00056 }
00057 
00058 WaveWidget::~WaveWidget()
00059 {
00060   if(wave_file != NULL) {
00061     if(wave_file->isOpen())
00062       wave_file->close();
00063     delete wave_file;
00064   }
00065   if(playdata != NULL)
00066     delete[] playdata;
00067   delete pthread;
00068   delete paint_lock;
00069   delete paint_timer;
00070 }
00071 
00072 bool WaveWidget::loadFile(QString const fname)
00073 {
00074   WaveFile *tmpwave;
00075   if(fname.right(4).upper() == ".OGG")
00076     tmpwave = new OggWave();
00077   else
00078     return false;               // no other file formats implemented yet
00079 
00080   if(!tmpwave->open(fname, xzoom)) {
00081     delete tmpwave;
00082     return false;
00083   }
00084 
00085   if(wave_file != NULL) {
00086     if(wave_file->isOpen())
00087       wave_file->close();
00088     delete wave_file;
00089   }
00090   wave_file = tmpwave;
00091 
00092   start_time = QTime(0, 0);
00093   end_time = QTime(0, 0, 2);
00094   left = QTime(0, 0);
00095   right = left.addSecs(xzoom);
00096   emit lengthChanged(MSECS(wave_file->length()) -
00097                     xzoom * 1000);
00098 
00099   return true;
00100 }
00101 
00102 bool WaveWidget::isVisible(QTime const t) const
00103 {
00104   return (t > left) & (t < right);
00105 }
00106 
00107 void WaveWidget::setStartTime(QTime t)
00108 {
00109   start_time = t;
00110   repaint();
00111 }
00112 
00113 void WaveWidget::setEndTime(QTime t)
00114 {
00115   end_time = t;
00116   repaint();
00117 }
00118 
00119 QTime WaveWidget::startTime() const 
00120 { 
00121   return start_time; 
00122 }
00123 
00124 QTime WaveWidget::endTime() const 
00125 { 
00126   return end_time; 
00127 }
00128 
00129 void WaveWidget::setXZoom(int zoom) 
00130 { 
00131   xzoom = (int)(std::pow(2.0, zoom - 1) * (640.0 / MAX_PIXPERSEC)); 
00132   right = left.addSecs(xzoom);
00133   if(SECS(wave_file->length()) < xzoom)
00134     emit lengthChanged(0);
00135   else
00136     emit lengthChanged(MSECS(wave_file->length()) - xzoom * 1000);
00137   wave_file->changeRes(xzoom);
00138   repaint(); 
00139 }
00140 
00141 void WaveWidget::setYZoom(int zoom) 
00142 { 
00143   yzoom = zoom; 
00144   repaint(); 
00145 }
00146 
00147 void WaveWidget::scrollTo(int start)
00148 {
00149   if(wave_file != NULL)
00150     if(wave_file->isOpen()) {
00151       if(SECS(wave_file->length()) < xzoom) {
00152         left = QTime(0, 0);
00153         right = left.addSecs(xzoom);
00154       } else if(SECS(wave_file->length()) - start < xzoom) {
00155         right = wave_file->length();
00156         left = QTIME_MS(MSECS(right) - xzoom * 1000);
00157       } else {
00158         right = QTIME_S(start).addSecs(xzoom);
00159         left = QTIME_S(start);
00160       }
00161       emit positionChanged(start);
00162       repaint();
00163     }
00164 }
00165 
00166 void WaveWidget::customEvent(QCustomEvent *e)
00167 {
00168   if(e->type() == (QEvent::Type)PlayThread::Finished) {
00169     playing = false;
00170     paint_timer->stop();
00171     repaint();
00172   }
00173 }
00174 
00175 void WaveWidget::mousePressEvent(QMouseEvent *e)
00176 {
00177   QTime tmp = left.addMSecs((int)((double)(1000.0 * xzoom) * 
00178                                   ((double)e->x() / (double)width())));
00179   QTime const max = wave_file->length();
00180   if(tmp < max)
00181     if(e->button() == Qt::LeftButton) {
00182       if(tmp > end_time) {
00183         end_time = tmp.addSecs(2);
00184         if(end_time > max)
00185           end_time = max;
00186         emit endTimeChanged(&end_time);
00187       }
00188       start_time = tmp;
00189       emit startTimeChanged(&start_time);
00190     }
00191     else if(e->button() == Qt::RightButton) {
00192       if(tmp >= start_time) {
00193         end_time = tmp;
00194         emit endTimeChanged(&end_time);
00195       }
00196     }
00197   repaint();
00198 }
00199 
00200 void WaveWidget::paintEvent(QPaintEvent *) 
00201 {
00202   QPixmap pm(width(), height());  
00203   QPainter p(&pm);
00204   QPen pen;
00205 
00206   pm.fill(QColor(10, 10, 10));
00207 
00208   if(wave_file != NULL)
00209     if(wave_file->isOpen()) {
00210       int tmp;
00211       int const t_width = 640, t_height = height();
00212       char *buf = new char[t_width * 2];
00213 
00214       wave_file->getDispBuffer(left, buf);
00215 
00216       p.setViewport(0, 0, t_width, t_height);
00217       p.setWindow(0, 0, t_width, t_height);
00218       pen.setWidth(1);
00219       pen.setColor(QColor(60, 60, 60));
00220       p.setPen(pen);
00221       p.drawLine(0, t_height / 2, t_width, t_height / 2);
00222       pen.setColor(QColor(120, 120, 120));
00223       p.setPen(pen);
00224       for(int i = 0; i < t_width; ++i) {
00225         int offs = (int)buf[i * 2] * yzoom / 10;
00226         if(offs > t_height / 2) offs = t_height / 2;
00227         if(offs < -t_height / 2) offs = -t_height / 2;
00228         p.drawLine(i, t_height / 2, i, t_height / 2 + offs);
00229         offs = (int)buf[i * 2 + 1] * yzoom / 10;
00230         if(offs > t_height / 2) offs = t_height / 2;
00231         if(offs < -t_height / 2) offs = -t_height / 2;
00232         p.drawLine(i, t_height / 2, i, t_height / 2 + offs);    
00233       }
00234       pen.setColor(QColor(30, 180, 30));
00235       p.setPen(pen);
00236       tmp = timeToPos(start_time);
00237       p.drawLine(tmp, 0, tmp, t_height-1);
00238       pen.setColor(QColor(180, 30, 30));
00239       p.setPen(pen);
00240       tmp = timeToPos(end_time);
00241       p.drawLine(tmp, 0, tmp, t_height-1);
00242 
00243 #ifdef WHITE_LINE
00244       if(playing) {
00245         pen.setColor(QColor(200, 200, 200));
00246         p.setPen(pen);
00247         paint_lock->lock();
00248         int const offset = (int)((double)(MSECS(play_end) - 
00249                                     MSECS(play_start)) * play_position);
00250         paint_lock->unlock();
00251         tmp = timeToPos(QTIME_MS(MSECS(play_start) + offset));
00252         p.drawLine(tmp, 0, tmp, t_height-1);
00253       }
00254 #endif // WHITE_LINE
00255 
00256       delete[] buf;
00257     }
00258   bitBlt(this, 0, 0, &pm);
00259 }
00260 
00261 void WaveWidget::playSelected()
00262 {
00263   if(playing)
00264     return;
00265   
00266   WaveFormat f;
00267   wave_file->waveFormat(f);
00268 
00269   char const *pcm_name = strdup("plughw:0,0");
00270   if(snd_pcm_open(&playback_handle, pcm_name, 
00271                   SND_PCM_STREAM_PLAYBACK, 0) < 0) {
00272     QMessageBox::critical(this, tr("Cannot open PCM device"),
00273                           tr("Cannot open the PCM device!"), 
00274                           QMessageBox::Cancel, QMessageBox::NoButton);
00275     return;
00276   }
00277   
00278   snd_pcm_hw_params_t *hw_params;
00279   if(snd_pcm_hw_params_malloc(&hw_params) < 0) {
00280     QMessageBox::critical(this, tr("Cannot configure PCM device"),
00281                           tr("Cannot configure the PCM device!"), 
00282                           QMessageBox::Cancel, QMessageBox::NoButton);
00283     return;
00284   }
00285   if(snd_pcm_hw_params_any(playback_handle, hw_params) < 0) {
00286     QMessageBox::critical(this, tr("Cannot configure PCM device"),
00287                           tr("Cannot configure the PCM device!"), 
00288                           QMessageBox::Cancel, QMessageBox::NoButton);
00289     return;
00290   }
00291 
00292   if(snd_pcm_hw_params_set_access(playback_handle, hw_params, f.access) < 0) {
00293     QMessageBox::critical(this, tr("Cannot set access mode"),
00294                           tr("Cannot set access mode!"), 
00295                           QMessageBox::Cancel, QMessageBox::NoButton);
00296     return;
00297   }
00298   if(snd_pcm_hw_params_set_format(playback_handle, hw_params, f.format) < 0) {
00299     QMessageBox::critical(this, tr("Cannot set PCM format"),
00300                           tr("Cannot set PCM format!"), 
00301                           QMessageBox::Cancel, QMessageBox::NoButton);
00302     return;
00303   }
00304   if(snd_pcm_hw_params_set_rate_near(playback_handle, 
00305                                      hw_params, &f.rate, 0) < 0) {
00306     QMessageBox::critical(this, tr("Cannot set PCM rate"),
00307                           tr("Cannot set PCM rate!"), 
00308                           QMessageBox::Cancel, QMessageBox::NoButton);
00309     return;
00310   }
00311   if(snd_pcm_hw_params_set_channels(playback_handle, 
00312                                     hw_params, f.channels) < 0) {
00313     QMessageBox::critical(this, tr("Cannot set the number of channels"),
00314                           tr("Cannot set the number of channels!"), 
00315                           QMessageBox::Cancel, QMessageBox::NoButton);
00316     return;
00317   }
00318 
00319   if(snd_pcm_hw_params(playback_handle, hw_params) < 0) {
00320     QMessageBox::critical(this, tr("Cannot configure PCM device"),
00321                           tr("Cannot configure the PCM device!"), 
00322                           QMessageBox::Cancel, QMessageBox::NoButton);
00323     return;
00324   }
00325   snd_pcm_hw_params_free(hw_params);
00326         
00327   if(snd_pcm_prepare(playback_handle) < 0) {
00328     QMessageBox::critical(this, tr("Cannot prepare PCM device"),
00329                           tr("Cannot prepare the PCM device!"), 
00330                           QMessageBox::Cancel, QMessageBox::NoButton);
00331     return;
00332   }
00333 
00334   playing = true;
00335   if(playdata != NULL)
00336     delete[] playdata;
00337   play_position = 0.0;
00338 
00339   playsize = wave_file->getPlayBufferSize(start_time, end_time);
00340   playdata = new char[playsize];
00341   wave_file->getPlayBuffer(start_time, playdata, playsize);
00342 
00343   pthread->initThread(this, playback_handle, paint_lock, &play_position);
00344   pthread->loadData(playdata, playsize, f);
00345   pthread->start();
00346 
00347 #ifdef WHITE_LINE
00348   play_start = start_time;
00349   play_end = end_time;
00350   paint_timer->start(PAINT_FREQ);
00351 #endif // WHITE_LINE
00352 }
00353 
00354 void WaveWidget::stopPlayback()
00355 {
00356   if(!playing)
00357     return;
00358 
00359   QApplication::postEvent(pthread, new QCustomEvent(PlayThread::Stop));
00360 }
00361 
00362 int WaveWidget::timeToPos(QTime t)
00363 {
00364   return (int)(((double)left.msecsTo(t) / (double)(1000.0 * xzoom)) * 
00365                (double)width());
00366 }

Projekt: SubTimer Készült: Wed Mar 23 22:06:54 2005 Készítette: doxygen 1.3.6