summaryrefslogtreecommitdiff
path: root/attic/muse_qt4_evolution/muse/waveedit/waveview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'attic/muse_qt4_evolution/muse/waveedit/waveview.cpp')
-rw-r--r--attic/muse_qt4_evolution/muse/waveedit/waveview.cpp1124
1 files changed, 1124 insertions, 0 deletions
diff --git a/attic/muse_qt4_evolution/muse/waveedit/waveview.cpp b/attic/muse_qt4_evolution/muse/waveedit/waveview.cpp
new file mode 100644
index 00000000..eb5a744d
--- /dev/null
+++ b/attic/muse_qt4_evolution/muse/waveedit/waveview.cpp
@@ -0,0 +1,1124 @@
+//=============================================================================
+// MusE
+// Linux Music Editor
+// $Id:$
+//
+// Copyright (C) 2002-2006 by Werner Schweer and others
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2.
+//
+// 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 <sys/wait.h>
+
+#include "waveview.h"
+#include "song.h"
+#include "midiedit/midieditor.h"
+#include "al/tempo.h"
+#include "event.h"
+#include "globals.h"
+#include "waveedit.h"
+#include "audio.h"
+#include "gconfig.h"
+#include "part.h"
+#include "widgets/simplebutton.h"
+#include "utils.h"
+
+static const int partLabelHeight = 13;
+
+//---------------------------------------------------------
+// WaveView
+//---------------------------------------------------------
+
+WaveView::WaveView(WaveEdit* pr)
+ : TimeCanvas(TIME_CANVAS_WAVEEDIT)
+ {
+ setMarkerList(song->marker());
+ curSplitter = -1;
+ dragSplitter = false;
+ selectionStart = 0;
+ selectionStop = 0;
+ lastGainvalue = 100;
+ editor = pr;
+
+ curPart = editor->parts()->begin()->second;
+ setMouseTracking(true);
+
+ songChanged(SC_TRACK_INSERTED);
+ }
+
+//---------------------------------------------------------
+// drawWavePart
+// y0 - start of track
+// th - track height
+// from - x pixel coordinate start drawing
+// to - x end drawing
+//
+// redraw area is QRect(from, y0, to-from, th)
+//---------------------------------------------------------
+
+void WaveView::drawWavePart(QPainter& p, Part* wp, int y0, int th, int from, int to)
+ {
+ int h = th/2;
+ int y = y0 + 1 + h;
+ int cc = th % 2 ? 0 : 1;
+
+ const Pos pos(pix2pos(from));
+ EventList* el = wp->events();
+ for (iEvent e = el->begin(); e != el->end(); ++e) {
+ Event event = e->second;
+ SndFileR f = event.sndFile();
+ if (f.isNull())
+ continue;
+ unsigned channels = f.channels();
+ if (channels == 0) {
+ printf("drawWavePart: channels==0! %s\n", f.finfo()->fileName().toLatin1().data());
+ continue;
+ }
+
+ int x1 = pos2pix(event.pos() + *wp);
+ int x2 = pos2pix(event.end() + *wp);
+ int w = x2 - x1;
+ if (w == 0)
+ continue;
+
+ int samples = event.lenFrame();
+ int xScale = (samples + w/2)/w;
+ int frame = pos.frame() - wp->frame()
+ - event.pos().frame() + event.spos();
+
+ if (h < 20) {
+ //
+ // combine multi channels into one waveform
+ //
+ for (int i = from; i < to; i++) {
+ SampleV sa[channels];
+ f.read(sa, xScale, frame);
+ frame += xScale;
+ int peak = 0;
+ int rms = 0;
+ for (unsigned k = 0; k < channels; ++k) {
+ if (sa[k].peak > peak)
+ peak = sa[k].peak;
+ rms += sa[k].rms;
+ }
+ rms /= channels;
+ peak = (peak * (th-2)) >> 9;
+ rms = (rms * (th-2)) >> 9;
+ p.setPen(QColor(Qt::darkGray));
+ p.drawLine(i, y - peak - cc, i, y + peak);
+ p.setPen(QColor(Qt::black));
+ p.drawLine(i, y - rms - cc, i, y + rms);
+ }
+ }
+ else {
+ //
+ // multi channel display
+ //
+ h = th / (channels * 2);
+ int cc = th % (channels * 2) ? 0 : 1;
+ for (int i = from; i < to; i++) {
+ y = y0 + 1 + h;
+ SampleV sa[channels];
+ f.read(sa, xScale, frame);
+ frame += xScale;
+ for (unsigned k = 0; k < channels; ++k) {
+ int peak = (sa[k].peak * (h - 1)) >> 8;
+ int rms = (sa[k].rms * (h - 1)) >> 8;
+ p.setPen(QColor(Qt::darkGray));
+ p.drawLine(i, y - peak - cc, i, y + peak);
+ p.setPen(QColor(Qt::black));
+ p.drawLine(i, y - rms - cc, i, y + rms);
+ y += 2 * h;
+ }
+ }
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// draw
+//---------------------------------------------------------
+
+void WaveView::paint(QPainter& p, QRect r)
+ {
+ QFont f = font();
+ f.setPointSize(8);
+ p.setFont(f);
+
+ int from = r.x();
+ int to = from + r.width();
+
+ PartList* pl = editor->parts();
+ for (iPart ip = pl->begin(); ip != pl->end(); ++ip) {
+ Part* part = ip->second;
+ int x1 = pos2pix(*part);
+ int x2 = pos2pix(part->end());
+ int len = x2 - x1;
+
+ if (x2 <= from)
+ continue;
+ if (x1 > to)
+ break;
+
+ int h = rCanvasA.height();
+ int xx1 = x1;
+ if (xx1 < from)
+ xx1 = from;
+ int xx2 = x2;
+ if (xx2 > to)
+ xx2 = to;
+ drawWavePart(p, part, 0, h, xx1, xx2);
+ int yy = h - partLabelHeight;
+ p.drawText(x1 + 3, yy, len - 6,
+ partLabelHeight-1, Qt::AlignVCenter | Qt::AlignLeft,
+ part->name());
+ }
+ }
+
+//---------------------------------------------------------
+// getCaption
+//---------------------------------------------------------
+
+QString WaveView::getCaption() const
+ {
+ QString caption("MusE: WaveEditor");
+ if (curPart)
+ return caption + QString(": ") + curPart->name();
+ return caption;
+ }
+
+//---------------------------------------------------------
+// songChanged
+//---------------------------------------------------------
+
+void WaveView::songChanged(int flags)
+ {
+ if (flags & ~SC_SELECTION) {
+ startFrame = MAXINT;
+ endFrame = 0;
+ for (iPart p = editor->parts()->begin(); p != editor->parts()->end(); ++p) {
+ Part* part = p->second;
+ int sframe = part->frame();
+ int eframe = sframe + part->lenFrame();
+ if (sframe < startFrame)
+ startFrame = sframe;
+ if (eframe > endFrame)
+ endFrame = eframe;
+ }
+ }
+// if (flags & SC_CLIP_MODIFIED) {
+// update(); // Boring, but the only thing possible to do
+// }
+ setPart(*curPart, curPart->end());
+ widget()->update();
+ }
+
+//---------------------------------------------------------
+// mousePress
+//---------------------------------------------------------
+
+void WaveView::mousePress(QMouseEvent* me)
+ {
+ QPoint pos(me->pos());
+
+ if (rCanvasA.contains(pos)) {
+// mousePressCanvasA(me);
+ return;
+ }
+ if (curSplitter != -1) {
+ dragSplitter = true;
+ splitterY = pos.y();
+ return;
+ }
+
+ if (rCanvasB.contains(pos)) {
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) {
+ CtrlEdit* c = *i;
+ QRect r(rCanvasB.x(), rCanvasB.y() + c->y + splitWidth,
+ rCanvasB.width(), c->cheight());
+ if (r.contains(pos)) {
+ c->mousePress(pos - r.topLeft(), me);
+ break;
+ }
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// mouseRelease
+//---------------------------------------------------------
+
+void WaveView::mouseRelease(QMouseEvent* me)
+ {
+ if (dragSplitter) {
+ dragSplitter = false;
+ return;
+ }
+ QPoint pos(me->pos());
+ if (rCanvasA.contains(pos)) {
+ // mouseReleaseCanvasA(me);
+ return;
+ }
+ if (rCanvasB.contains(pos)) {
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) {
+ CtrlEdit* c = *i;
+ QRect r(rCanvasB.x(), rCanvasB.y() + c->y + splitWidth,
+ rCanvasB.width(), c->cheight());
+ if (r.contains(pos)) {
+ c->mouseRelease();
+ break;
+ }
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// mouseMove
+//---------------------------------------------------------
+
+void WaveView::mouseMove(QPoint pos)
+ {
+ if (dragSplitter) {
+ int deltaY = pos.y() - splitterY;
+
+ iCtrlEdit i = ctrlEditList.begin();
+ int y = 0;
+ if (curSplitter > 0) {
+ int k = 0;
+ CtrlEdit* c = 0;
+ for (; i != ctrlEditList.end(); ++i, ++k) {
+ c = *i;
+ y += c->height();
+ if ((k+1) == curSplitter)
+ break;
+ }
+ if (i == ctrlEditList.end()) {
+ printf("unexpected edit list end, curSplitter %d\n", curSplitter);
+ return;
+ }
+ if (c->height() + deltaY < splitWidth)
+ deltaY = splitWidth - c->height();
+ ++i;
+ int rest = 0;
+ for (iCtrlEdit ii = i; ii != ctrlEditList.end(); ++ii)
+ rest += (*ii)->cheight();
+ if (rest < deltaY)
+ deltaY = rest;
+ c->setHeight(c->height() + deltaY);
+ layoutPanelB(c);
+ y += deltaY;
+ }
+ //
+ // layout rest, add deltaY vertical
+ //
+ int rest = 0;
+ for (iCtrlEdit ii = i; ii != ctrlEditList.end(); ++ii) {
+ CtrlEdit* c = *ii;
+ rest += c->cheight();
+ }
+ if (rest < deltaY)
+ deltaY = rest;
+ rest = deltaY;
+ for (; i != ctrlEditList.end(); ++i) {
+ CtrlEdit* c = *i;
+ int d = c->cheight();
+ if (d > deltaY)
+ d = deltaY;
+ c->setHeight(c->height() - d);
+ c->y = y;
+ layoutPanelB(c);
+ y += c->height();
+ deltaY -= d;
+ if (deltaY == 0)
+ break;
+ }
+ if (i != ctrlEditList.end())
+ ++i;
+ for (; i != ctrlEditList.end(); ++i) {
+ CtrlEdit* c = *i;
+ c->y = y;
+ y += c->height();
+ }
+ if (curSplitter == 0)
+ resizeController(ctrlHeight - rest);
+ else
+ widget()->update(rPanelB | rCanvasB);
+ splitterY = pos.y();
+ updatePartControllerList();
+ return;
+ }
+ if (rCanvasA.contains(pos)) {
+ // mouseMoveCanvasA(pos - rCanvasA.topLeft());
+ return;
+ }
+ if (button == 0) {
+ if (rPanelB.contains(pos) || rCanvasB.contains(pos)) {
+ int y = pos.y() - rPanelB.y();
+ int k = 0;
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i, ++k) {
+ CtrlEdit* c = *i;
+ if (y >= c->y && y < (c->y + splitWidth)) {
+ curSplitter = k;
+ setCursor();
+ return;
+ }
+ int ypos = y - c->y - splitWidth;
+ if (ypos >= 0)
+ emit yChanged(c->pixel2val(ypos));
+ }
+ }
+ if (curSplitter != -1) {
+ curSplitter = -1;
+ setCursor();
+ }
+ return;
+ }
+ if (rCanvasB.contains(pos)) {
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) {
+ CtrlEdit* c = *i;
+ QRect r(rCanvasB.x(), rCanvasB.y() + c->y + splitWidth,
+ rCanvasB.width(), c->cheight());
+ if (r.contains(pos)) {
+ c->mouseMove(pos - r.topLeft());
+ break;
+ }
+ }
+ }
+
+ }
+
+//---------------------------------------------------------
+// cmd
+//---------------------------------------------------------
+
+void WaveView::cmd(const QString&)
+ {
+#if 0
+ int modifyoperation = -1;
+ double paramA = 0.0;
+
+ switch(n) {
+ case WaveEdit::CMD_SELECT_ALL:
+ if (!editor->parts()->empty()) {
+ iPart iBeg = editor->parts()->begin();
+ iPart iEnd = editor->parts()->end();
+ iEnd--;
+ Part* beg = iBeg->second;
+ Part* end = iEnd->second;
+ selectionStart = beg->frame();
+ selectionStop = end->frame() + end->lenFrame();
+ update();
+ }
+ break;
+
+ case WaveEdit::CMD_EDIT_EXTERNAL:
+ modifyoperation = EDIT_EXTERNAL;
+ break;
+
+ case WaveEdit::CMD_SELECT_NONE:
+ selectionStart = selectionStop = 0;
+ update();
+ break;
+
+ case WaveEdit::CMD_MUTE:
+ modifyoperation = MUTE;
+ break;
+
+ case WaveEdit::CMD_NORMALIZE:
+ modifyoperation = NORMALIZE;
+ break;
+
+ case WaveEdit::CMD_FADE_IN:
+ modifyoperation = FADE_IN;
+ break;
+
+ case WaveEdit::CMD_FADE_OUT:
+ modifyoperation = FADE_OUT;
+ break;
+
+ case WaveEdit::CMD_REVERSE:
+ modifyoperation = REVERSE;
+ break;
+
+ case WaveEdit::CMD_GAIN_FREE: {
+ /*
+ EditGain* editGain = new EditGain(this, lastGainvalue);
+ if (editGain->exec() == QDialog::Accepted) {
+ lastGainvalue = editGain->getGain();
+ modifyoperation = GAIN;
+ paramA = (double)lastGainvalue / 100.0;
+ }
+ delete editGain;
+ */
+ printf("Free gain - todo!\n");
+ }
+ break;
+
+ case WaveEdit::CMD_GAIN_200:
+ modifyoperation = GAIN;
+ paramA = 2.0;
+ break;
+
+ case WaveEdit::CMD_GAIN_150:
+ modifyoperation = GAIN;
+ paramA = 1.5;
+ break;
+
+ case WaveEdit::CMD_GAIN_75:
+ modifyoperation = GAIN;
+ paramA = 0.75;
+ break;
+
+ case WaveEdit::CMD_GAIN_50:
+ modifyoperation = GAIN;
+ paramA = 0.5;
+ break;
+
+ case WaveEdit::CMD_GAIN_25:
+ modifyoperation = GAIN;
+ paramA = 0.25;
+ break;
+
+ default:
+ break;
+ }
+
+ if (modifyoperation != -1) {
+ if (selectionStart == selectionStop) {
+ printf("No selection. Ignoring\n"); //@!TODO: Disable menu options when no selection
+ return;
+ }
+ modifySelection(modifyoperation, selectionStart, selectionStop, paramA);
+ }
+#endif
+ }
+
+//---------------------------------------------------------
+// getSelection
+//---------------------------------------------------------
+
+WaveSelectionList WaveView::getSelection(unsigned /*startpos*/, unsigned /*stoppos*/)
+ {
+ WaveSelectionList selection;
+#if 0
+ for (iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) {
+ Part* wp = ip->second;
+ unsigned part_offset = wp->frame();
+ EventList* el = wp->events();
+
+ for (iEvent e = el->begin(); e != el->end(); ++e) {
+ Event event = e->second;
+ if (event.empty())
+ continue;
+ SndFileR file = event.sndFile();
+ if (file.isNull())
+ continue;
+
+ unsigned event_offset = event.frame() + part_offset;
+ unsigned event_startpos = event.spos();
+ unsigned event_length = event.lenFrame() + event.spos();
+ unsigned event_end = event_offset + event_length;
+ //printf("startpos=%d stoppos=%d part_offset=%d event_offset=%d event_startpos=%d event_length=%d event_end=%d\n", startpos, stoppos, part_offset, event_offset, event_startpos, event_length, event_end);
+
+ if (!(event_end <= startpos || event_offset >= stoppos)) {
+ int tmp_sx = startpos - event_offset + event_startpos;
+ int tmp_ex = stoppos - event_offset + event_startpos;
+ unsigned sx;
+ unsigned ex;
+
+ tmp_sx < (int)event_startpos ? sx = event_startpos : sx = tmp_sx;
+ tmp_ex > (int)event_length ? ex = event_length : ex = tmp_ex;
+
+ //printf("Event data affected: %d->%d filename:%s\n", sx, ex, file.name().toLatin1().data());
+ WaveEventSelection s;
+ s.file = file;
+ s.startframe = sx;
+ s.endframe = ex;
+ selection.push_back(s);
+ }
+ }
+ }
+#endif
+ return selection;
+ }
+
+//---------------------------------------------------------
+// modifySelection
+//---------------------------------------------------------
+
+void WaveView::modifySelection(int /*operation*/, unsigned /*startpos*/, unsigned /*stoppos*/, double /*paramA*/)
+ {
+#if 0
+ song->startUndo();
+
+ WaveSelectionList selection = getSelection(startpos, stoppos);
+ for (iWaveSelection i = selection.begin(); i != selection.end(); i++) {
+ WaveEventSelection w = *i;
+ SndFileR& file = w.file;
+ unsigned sx = w.startframe;
+ unsigned ex = w.endframe;
+ unsigned file_channels = file.channels();
+
+ QString tmpWavFile = QString::null;
+ if (!getUniqueTmpfileName(tmpWavFile)) {
+ break;
+ }
+
+ audio->msgIdle(true); // Not good with playback during operations
+ SndFile tmpFile(tmpWavFile);
+ tmpFile.setFormat(file.format(), file_channels, file.samplerate());
+ if (tmpFile.openWrite()) {
+ audio->msgIdle(false);
+ printf("Could not open temporary file...\n");
+ break;
+ }
+
+ //
+ // Write out data that will be changed to temp file
+ //
+ unsigned tmpdatalen = ex - sx;
+ off_t tmpdataoffset = sx;
+ float* tmpdata[file_channels];
+
+ for (unsigned i=0; i<file_channels; i++) {
+ tmpdata[i] = new float[tmpdatalen];
+ }
+
+ file.seek(tmpdataoffset, 0);
+ file.read(file_channels, tmpdata, tmpdatalen);
+ file.close();
+ tmpFile.write(file_channels, tmpdata, tmpdatalen);
+ tmpFile.close();
+
+ switch(operation)
+ {
+ case MUTE:
+ muteSelection(file_channels, tmpdata, tmpdatalen);
+ break;
+
+ case NORMALIZE:
+ normalizeSelection(file_channels, tmpdata, tmpdatalen);
+ break;
+
+ case FADE_IN:
+ fadeInSelection(file_channels, tmpdata, tmpdatalen);
+ break;
+
+ case FADE_OUT:
+ fadeOutSelection(file_channels, tmpdata, tmpdatalen);
+ break;
+
+ case REVERSE:
+ reverseSelection(file_channels, tmpdata, tmpdatalen);
+ break;
+
+ case GAIN:
+ applyGain(file_channels, tmpdata, tmpdatalen, paramA);
+ break;
+
+ case EDIT_EXTERNAL:
+ editExternal(file.format(), file.samplerate(), file_channels, tmpdata, tmpdatalen);
+ break;
+
+ default:
+ printf("Error: Default state reached in modifySelection\n");
+ break;
+
+ }
+
+ file.openWrite();
+ file.seek(tmpdataoffset, 0);
+ file.write(file_channels, tmpdata, tmpdatalen);
+ file.update();
+ file.close();
+ file.openRead();
+
+ for (unsigned i=0; i<file_channels; i++) {
+ delete[] tmpdata[i];
+ }
+
+ // Undo handling
+ song->cmdChangeWave(file.dirPath() + "/" + file.name(), tmpWavFile, sx, ex);
+ audio->msgIdle(false); // Not good with playback during operations
+ }
+ song->endUndo(SC_CLIP_MODIFIED);
+ update();
+#endif
+ }
+
+//---------------------------------------------------------
+// muteSelection
+//---------------------------------------------------------
+
+void WaveView::muteSelection(unsigned /*channels*/, float** /*data*/, unsigned /*length*/)
+ {
+#if 0
+ // Set everything to 0!
+ for (unsigned i=0; i<channels; i++) {
+ for (unsigned j=0; j<length; j++) {
+ data[i][j] = 0;
+ }
+ }
+#endif
+ }
+
+//---------------------------------------------------------
+// normalizeSelection
+//---------------------------------------------------------
+
+void WaveView::normalizeSelection(unsigned /*channels*/, float** /*data*/, unsigned /*length*/)
+ {
+#if 0
+ float loudest = 0.0;
+
+ for (unsigned i=0; i<channels; i++) {
+ for (unsigned j=0; j<length; j++) {
+ if (data[i][j] > loudest)
+ loudest = data[i][j];
+ }
+ }
+
+ double scale = 0.99 / (double)loudest;
+
+ for (unsigned i=0; i<channels; i++) {
+ for (unsigned j=0; j<length; j++) {
+ data[i][j] = (float) ((double)data[i][j] * scale);
+ }
+ }
+#endif
+ }
+
+//---------------------------------------------------------
+// fadeInSelection
+//---------------------------------------------------------
+
+void WaveView::fadeInSelection(unsigned /*channels*/, float** /*data*/, unsigned /*length*/)
+ {
+#if 0
+ for (unsigned i=0; i<channels; i++) {
+ for (unsigned j=0; j<length; j++) {
+ double scale = (double) j / (double)length ;
+ data[i][j] = (float) ((double)data[i][j] * scale);
+ }
+ }
+#endif
+ }
+
+//---------------------------------------------------------
+// fadeOutSelection
+//---------------------------------------------------------
+
+void WaveView::fadeOutSelection(unsigned /*channels*/, float** /*data*/, unsigned /*length*/)
+ {
+#if 0
+ for (unsigned i=0; i<channels; i++) {
+ for (unsigned j=0; j<length; j++) {
+ double scale = (double) (length - j) / (double)length ;
+ data[i][j] = (float) ((double)data[i][j] * scale);
+ }
+ }
+#endif
+ }
+
+//---------------------------------------------------------
+// reverseSelection
+//---------------------------------------------------------
+
+void WaveView::reverseSelection(unsigned channels, float** data, unsigned length)
+ {
+ for (unsigned i=0; i<channels; i++) {
+ for (unsigned j=0; j<length/2; j++) {
+ float tmpl = data[i][j];
+ float tmpr = data[i][length - j];
+ data[i][j] = tmpr;
+ data[i][length - j] = tmpl;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// applyGain
+//---------------------------------------------------------
+
+void WaveView::applyGain(unsigned channels, float** data, unsigned length, double gain)
+ {
+ for (unsigned i=0; i<channels; i++) {
+ for (unsigned j=0; j<length; j++) {
+ data[i][j] = (float) ((double)data[i][j] * gain);
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// editExternal
+//---------------------------------------------------------
+
+void WaveView::editExternal(unsigned file_format, unsigned file_samplerate, unsigned file_channels, float** tmpdata, unsigned tmpdatalen)
+ {
+ // Create yet another tmp-file
+ QString exttmpFileName;
+ if (!getUniqueTmpfileName(exttmpFileName)) {
+ printf("Could not create temp file - aborting...\n");
+ return;
+ }
+
+ SndFile exttmpFile(exttmpFileName);
+ exttmpFile.setFormat(file_format, file_channels, file_samplerate);
+ if (exttmpFile.openWrite()) {
+ printf("Could not open temporary file...\n");
+ return;
+ }
+ // Write out change-data to this file:
+ exttmpFile.write(file_channels, tmpdata, tmpdatalen);
+ exttmpFile.close();
+
+ // Forkaborkabork
+ int pid = vfork();
+ if (pid == 0) {
+ if (execlp(config.externalWavEditor.toLatin1().data(), "", exttmpFileName.toLatin1().data(), NULL) == -1) {
+ perror("Failed to launch external editor");
+ // Get out of here
+ exit(-1);
+ }
+ //@!TODO: Handle unsuccessful attempts
+ }
+ else if (pid == -1) {
+ perror("fork failed");
+ }
+ else {
+ waitpid(pid, 0, 0);
+ if (exttmpFile.openRead()) {
+ printf("Could not reopen temporary file again!\n");
+ }
+ else {
+ // Re-read file again
+ exttmpFile.seek(0);
+ size_t sz = exttmpFile.read(file_channels, tmpdata, tmpdatalen);
+ if (sz != tmpdatalen) {
+ // File must have been shrunken - not good. Alert user.
+ QMessageBox::critical(this, tr("MusE - file size changed"),
+ tr("When editing in external editor - you should not change the filesize\nsince it must fit the selected region.\n\nMissing data is muted"));
+ for (unsigned i=0; i<file_channels; i++) {
+ for (unsigned j=sz; j<tmpdatalen; j++) {
+ tmpdata[i][j] = 0;
+ }
+ }
+ }
+ }
+ QDir dir = exttmpFile.finfo()->absolutePath();
+ dir.remove(exttmpFileName);
+ dir.remove(exttmpFile.finfo()->baseName() + ".wca");
+ }
+ }
+
+//---------------------------------------------------------
+// getUniqueTmpfileName
+//---------------------------------------------------------
+
+bool WaveView::getUniqueTmpfileName(QString& newFilename)
+ {
+ // Check if tmp-directory exists under project path
+ QString tmpWavDir = song->absoluteProjectPath() + "/tmp_musewav"; //!@TODO: Don't hardcode like this
+ QFileInfo tmpdirfi(tmpWavDir);
+ if (!tmpdirfi.isDir()) {
+ // Try to create a tmpdir
+ QDir projdir(song->absoluteProjectPath());
+ if (!projdir.mkdir("tmp_musewav")) {
+ printf("Could not create undo dir!\n");
+ return false;
+ }
+ }
+
+
+ tmpdirfi.setFile(tmpWavDir);
+
+ if (!tmpdirfi.isWritable()) {
+ printf("Temp directory is not writable - aborting\n");
+ return false;
+ }
+
+ QDir tmpdir = tmpdirfi.dir();
+
+ // Find a new filename
+ for (int i=0; i<10000; i++) {
+ QString filename = "muse_tmp";
+ filename.append(QString::number(i));
+ filename.append(".wav");
+
+ if (!tmpdir.exists(tmpWavDir +"/" + filename)) {
+ newFilename = tmpWavDir + "/" + filename;
+ return true;
+ }
+ }
+
+ printf("Could not find a suitable tmpfilename (more than 10000 tmpfiles in tmpdir - clean up!\n");
+ return false;
+ }
+
+//---------------------------------------------------------
+// range
+//---------------------------------------------------------
+
+void WaveView::range(AL::Pos& s, AL::Pos& e) const
+ {
+ s.setFrame(startFrame);
+ e.setFrame(endFrame);
+ }
+
+//---------------------------------------------------------
+// layout
+//---------------------------------------------------------
+
+void WaveView::layout()
+ {
+ int n = ctrlEditList.size();
+ if (n == 0)
+ return;
+ if (ctrlHeight == 0) {
+ int wh = widget()->height();
+ resizeController(wh < 120 ? wh / 2 : 100);
+ }
+ // check, if layout is ok already; this happens after
+ // song load
+ int h = 0;
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) {
+ CtrlEdit* c = *i;
+ h += c->height();
+ }
+ if (h == ctrlHeight) {
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i)
+ layoutPanelB(*i);
+ return;
+ }
+ int y = 0;
+ int sch = ctrlHeight / n;
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) {
+ CtrlEdit* c = *i;
+ c->y = y;
+ c->setHeight(sch);
+ layoutPanelB(c);
+ y += sch;
+ }
+ }
+
+//---------------------------------------------------------
+// layout1
+//---------------------------------------------------------
+
+void WaveView::layout1()
+ {
+ int n = ctrlEditList.size();
+ if (n == 0)
+ return;
+ int y = 0;
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) {
+ CtrlEdit* c = *i;
+ c->y = y;
+ y += c->height();
+ }
+ resizeController(y);
+ }
+
+//---------------------------------------------------------
+// layoutPanelB
+//---------------------------------------------------------
+
+void WaveView::layoutPanelB(CtrlEdit* c)
+ {
+ int y = c->y;
+ int h = c->height();
+ int bx = rPanelB.x() + rPanelB.width() - 23;
+ int by = rPanelB.y() + y + h - 19;
+ c->minus->setGeometry(bx, by, 18, 18);
+ bx = rPanelB.x() + 1;
+ by = rPanelB.y() + y + 5;
+ c->sel->setGeometry(bx, by, rPanelB.width() - 5, 18);
+ }
+
+//---------------------------------------------------------
+// addController
+//---------------------------------------------------------
+
+void WaveView::addController()
+ {
+ int n = ctrlEditList.size();
+ CtrlEdit* ce = new CtrlEdit(widget(), this, curPart->track());
+ ce->setHeight(50);
+ ctrlEditList.push_back(ce);
+
+ ce->minus->defaultAction()->setData(n);
+ connect(ce->minus, SIGNAL(triggered(QAction*)), SLOT(removeController(QAction*)));
+ ce->minus->show();
+ ce->sel->show();
+
+ layout();
+ widget()->update();
+ updatePartControllerList();
+ }
+
+void WaveView::addController(int id, int h)
+ {
+ ctrlHeight += h;
+ int n = ctrlEditList.size();
+
+ CtrlEdit* ce = new CtrlEdit(widget(), this, curPart->track());
+ ce->setHeight(h);
+ ce->setCtrl(id);
+ ctrlEditList.push_back(ce);
+
+ ce->minus->defaultAction()->setData(n);
+ connect(ce->minus, SIGNAL(triggered(QAction*)), SLOT(removeController(QAction*)));
+ }
+
+//---------------------------------------------------------
+// removeController
+//---------------------------------------------------------
+
+void WaveView::removeController(QAction* a)
+ {
+ int id = a->data().toInt();
+
+ int k = 0;
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i, ++k) {
+ if (k == id) {
+ CtrlEdit* c = *i;
+ delete c;
+ ctrlEditList.erase(i);
+ break;
+ }
+ }
+ k = 0;
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i, ++k) {
+ CtrlEdit* c = *i;
+ c->minus->defaultAction()->setData(k);
+ }
+
+ if (ctrlEditList.empty())
+ resizeController(0);
+ else
+ layout();
+ widget()->update();
+ updatePartControllerList();
+ }
+
+//---------------------------------------------------------
+// updatePartControllerList
+//---------------------------------------------------------
+
+void WaveView::updatePartControllerList()
+ {
+ if (curPart == 0)
+ return;
+ CtrlCanvasList* cl = curPart->getCtrlCanvasList();
+ cl->clear();
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) {
+ CtrlCanvas cc;
+ cc.ctrlId = (*i)->ctrlId;
+ cc.height = (*i)->height();
+ cl->push_back(cc);
+ }
+ }
+
+//---------------------------------------------------------
+// paintControllerCanvas
+// r(0, 0) is PanelB topLeft()
+//---------------------------------------------------------
+
+void WaveView::paintControllerCanvas(QPainter& p, QRect r)
+ {
+ int x1 = r.x();
+ int x2 = x1 + r.width();
+
+ int xx2 = rCanvasB.width();
+ if (xx2 >= x2)
+ x2 = xx2 - 2;
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) {
+ CtrlEdit* c = *i;
+ int y = c->y;
+ paintHLine(p, x1, x2, y);
+ p.setPen(lineColor[0]);
+ p.drawLine(xx2-1, 1, xx2-1, splitWidth-2);
+
+ QRect rc(0, y + splitWidth, rCanvasB.width(), c->cheight());
+ QPoint pt(rc.topLeft());
+ rc &= r;
+ if (!rc.isEmpty()) {
+ p.translate(pt);
+ c->paint(p, rc.translated(-pt));
+ p.translate(-pt);
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// paintControllerPanel
+// panelB
+//---------------------------------------------------------
+
+void WaveView::paintControllerPanel(QPainter& p, QRect r)
+ {
+ p.fillRect(r, QColor(0xe0, 0xe0, 0xe0));
+ int x1 = r.x();
+ int x2 = x1 + r.width();
+
+ paintVLine(p, r.y() + splitWidth, r.y() + r.height(),
+ rPanelB.x() + rPanelB.width());
+
+ if (x1 == 0)
+ x1 = 1;
+ for (iCtrlEdit i = ctrlEditList.begin(); i != ctrlEditList.end(); ++i) {
+ CtrlEdit* c = *i;
+ paintHLine(p, x1, x2, c->y);
+ p.setPen(lineColor[0]);
+ p.drawLine(0, 1, 0, splitWidth-2);
+ }
+ }
+
+//---------------------------------------------------------
+// setCursor
+//---------------------------------------------------------
+
+void WaveView::setCursor()
+ {
+ if (curSplitter != -1) {
+ widget()->setCursor(Qt::SplitVCursor);
+ return;
+ }
+ TimeCanvas::setCursor();
+ }
+
+//---------------------------------------------------------
+// enterB
+//---------------------------------------------------------
+
+void WaveView::enterB()
+ {
+ if ((button == 0) && curSplitter != -1) {
+ curSplitter = -1;
+ setCursor();
+ }
+ }
+
+//---------------------------------------------------------
+// leaveB
+//---------------------------------------------------------
+
+void WaveView::leaveB()
+ {
+ if ((button == 0) && (curSplitter != -1)) {
+ curSplitter = -1;
+ setCursor();
+ }
+ }
+
+