00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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;
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 }