summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2012-08-15 00:24:29 +0000
committerTim E. Real <termtech@rogers.com>2012-08-15 00:24:29 +0000
commit6c642a1cff928c183d80af7ab4fad6910466a091 (patch)
treeab534d2203486d681398b7197635861ae65160c1
parent345fb0cc41b94b08134dc1f40020b4bf26e1d46b (diff)
Introducing: Improved Wave Editor. Class WaveView is replaced by WaveCanvas.
Wave Events can be selected, added, moved and deleted. TODO: Bunch o' stuff, but currently it should be as good or better than the old editor.
-rw-r--r--muse2/ChangeLog5
-rw-r--r--muse2/muse/functions.cpp12
-rw-r--r--muse2/muse/midiedit/ecanvas.h16
-rw-r--r--muse2/muse/midieditor.cpp22
-rw-r--r--muse2/muse/midieditor.h5
-rw-r--r--muse2/muse/waveedit/CMakeLists.txt4
-rw-r--r--muse2/muse/waveedit/wavecanvas.cpp2422
-rw-r--r--muse2/muse/waveedit/wavecanvas.h185
-rw-r--r--muse2/muse/waveedit/waveedit.cpp401
-rw-r--r--muse2/muse/waveedit/waveedit.h27
-rw-r--r--muse2/muse/widgets/canvas.cpp2
-rw-r--r--muse2/muse/widgets/canvas.h2
-rw-r--r--muse2/muse/widgets/poslabel.cpp24
13 files changed, 3032 insertions, 95 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog
index 8cd17adf..0c3883f7 100644
--- a/muse2/ChangeLog
+++ b/muse2/ChangeLog
@@ -1,3 +1,8 @@
+14.08.2012:
+ * Introducing: Improved Wave Editor. (Tim)
+ Class WaveView is replaced by WaveCanvas.
+ Wave Events can be selected, added, moved and deleted.
+ TODO: Bunch o' stuff, but currently it should be as good or better than the old editor.
04.08.2012:
* Introducing: More bits for Song Changed SC_* flags. (Tim)
Added MusECore::SongChangedFlags_t (in new type_defs.h file). Declared as int64 type.
diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp
index 1a6927e8..da5826e5 100644
--- a/muse2/muse/functions.cpp
+++ b/muse2/muse/functions.cpp
@@ -1286,12 +1286,22 @@ void schedule_resize_all_same_len_clone_parts(Part* part, unsigned new_len, Undo
if (op_it->type==UndoOp::ModifyPart || op_it->type==UndoOp::DeletePart)
already_done.insert(op_it->nPart);
- unsigned old_len=part->lenTick();
+ unsigned old_len= part->type() == Pos::FRAMES ? part->lenFrame() : part->lenTick();
if (old_len!=new_len)
{
Part* part_it=part;
do
{
+ if (part->type() == Pos::FRAMES)
+ {
+ if (part_it->lenFrame()==old_len && !already_done.contains(part_it))
+ {
+ WavePart* new_part = new WavePart(*(WavePart*)part_it);
+ new_part->setLenFrame(new_len);
+ operations.push_back(UndoOp(UndoOp::ModifyPart, part_it, new_part, true, false));
+ }
+ }
+ else
if (part_it->lenTick()==old_len && !already_done.contains(part_it))
{
MidiPart* new_part = new MidiPart(*(MidiPart*)part_it);
diff --git a/muse2/muse/midiedit/ecanvas.h b/muse2/muse/midiedit/ecanvas.h
index 7847e88a..400072dc 100644
--- a/muse2/muse/midiedit/ecanvas.h
+++ b/muse2/muse/midiedit/ecanvas.h
@@ -87,22 +87,22 @@ class EventCanvas : public Canvas {
signals:
void pitchChanged(int); // current cursor position
void timeChanged(unsigned);
- void selectionChanged(int /*tick*/ , MusECore::Event&, MusECore::Part*, bool /*update*/);
+ void selectionChanged(int /*tick or frame*/ , MusECore::Event&, MusECore::Part*, bool /*update*/);
void enterCanvas();
public:
EventCanvas(MidiEditor*, QWidget*, int, int, const char* name = 0);
MusECore::MidiTrack* track() const;
- unsigned start() const { return start_tick; }
- unsigned end() const { return end_tick; }
+ virtual unsigned start() const { return start_tick; }
+ virtual unsigned end() const { return end_tick; }
bool midiin() const { return _midiin; }
bool steprec() const { return _steprec; }
- QString getCaption() const;
- void songChanged(MusECore::SongChangedFlags_t);
- void range(int* s, int* e) const { *s = start_tick; *e = end_tick; }
+ virtual QString getCaption() const;
+ virtual void songChanged(MusECore::SongChangedFlags_t);
+ virtual void range(int* s, int* e) const { *s = start_tick; *e = end_tick; }
void playEvents(bool flag) { _playEvents = flag; }
- void selectAtTick(unsigned int tick);
- void viewDropEvent(QDropEvent* event);
+ virtual void selectAtTick(unsigned int tick);
+ virtual void viewDropEvent(QDropEvent* event);
virtual void modifySelected(NoteInfo::ValType, int /*val*/, bool /*delta_mode*/ = true) {}
virtual void keyPress(QKeyEvent*);
};
diff --git a/muse2/muse/midieditor.cpp b/muse2/muse/midieditor.cpp
index b4830c21..c00a7049 100644
--- a/muse2/muse/midieditor.cpp
+++ b/muse2/muse/midieditor.cpp
@@ -50,7 +50,7 @@ MidiEditor::MidiEditor(ToplevelType t, int r, MusECore::PartList* pl,
_parts.insert(i->second->sn());
_raster = r;
canvas = 0;
- wview = 0;
+ //wview = 0;
_curDrumInstrument = -1;
mainw = new QWidget(this);
@@ -194,8 +194,8 @@ void MidiEditor::songChanged(MusECore::SongChangedFlags_t type)
}
if (canvas)
canvas->songChanged(type);
- else if (wview)
- wview->songChanged(type);
+ //else if (wview)
+ // wview->songChanged(type);
if (type & (SC_PART_REMOVED | SC_PART_MODIFIED
| SC_PART_INSERTED | SC_TRACK_REMOVED)) {
@@ -204,8 +204,8 @@ void MidiEditor::songChanged(MusECore::SongChangedFlags_t type)
if (canvas)
setWindowTitle(canvas->getCaption());
- else if (wview)
- setWindowTitle(wview->getCaption());
+ //else if (wview)
+ // setWindowTitle(wview->getCaption());
if (type & SC_SIG)
time->update();
@@ -236,18 +236,6 @@ MusECore::Part* MidiEditor::curCanvasPart()
}
//---------------------------------------------------------
-// curWavePart
-//---------------------------------------------------------
-
-MusECore::WavePart* MidiEditor::curWavePart()
-{
- if(wview)
- return wview->part();
- else
- return 0;
-}
-
-//---------------------------------------------------------
// setCurCanvasPart
//---------------------------------------------------------
diff --git a/muse2/muse/midieditor.h b/muse2/muse/midieditor.h
index fd6d255b..541e4e0c 100644
--- a/muse2/muse/midieditor.h
+++ b/muse2/muse/midieditor.h
@@ -46,7 +46,7 @@ class CtrlEdit;
class EventCanvas;
class MTScale;
class ScrollScale;
-class WaveView;
+//class WaveView;
//---------------------------------------------------------
// MidiEditor
@@ -64,7 +64,7 @@ class MidiEditor : public TopWin {
MusEGui::ScrollScale* vscroll;
MusEGui::MTScale* time;
EventCanvas* canvas;
- WaveView* wview;
+ //WaveView* wview;
std::list<CtrlEdit*> ctrlEditList;
int _raster;
@@ -102,7 +102,6 @@ class MidiEditor : public TopWin {
MusECore::PartList* parts() { return _pl; }
int curDrumInstrument() const { return _curDrumInstrument; }
MusECore::Part* curCanvasPart();
- MusECore::WavePart* curWavePart();
void setCurCanvasPart(MusECore::Part*);
void addPart(MusECore::Part*);
};
diff --git a/muse2/muse/waveedit/CMakeLists.txt b/muse2/muse/waveedit/CMakeLists.txt
index f32eb6e1..920c7068 100644
--- a/muse2/muse/waveedit/CMakeLists.txt
+++ b/muse2/muse/waveedit/CMakeLists.txt
@@ -27,7 +27,7 @@
QT4_WRAP_CPP ( waveedit_mocs
editgain.h
waveedit.h
- waveview.h
+ wavecanvas.h
)
##
@@ -44,7 +44,7 @@ QT4_WRAP_UI (waveedit_ui_headers ${waveedit_ui_files} )
file (GLOB waveedit_source_files
editgain.cpp
waveedit.cpp
- waveview.cpp
+ wavecanvas.cpp
)
##
diff --git a/muse2/muse/waveedit/wavecanvas.cpp b/muse2/muse/waveedit/wavecanvas.cpp
new file mode 100644
index 00000000..220c2804
--- /dev/null
+++ b/muse2/muse/waveedit/wavecanvas.cpp
@@ -0,0 +1,2422 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// wavecanvas.cpp
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
+//
+// Based on WaveView.cpp and PianoCanvas.cpp
+// (C) Copyright 2000 Werner Schweer (ws@seh.de)
+// and others.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; version 2 of
+// the License, or (at your option) any later version.
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=========================================================
+
+
+#include <QApplication>
+#include <QClipboard>
+#include <QPainter>
+#include <QDrag>
+#include <QDragLeaveEvent>
+#include <QDragEnterEvent>
+#include <QDragMoveEvent>
+#include <QDropEvent>
+#include <QMouseEvent>
+#include <QList>
+#include <QPair>
+#include <QMessageBox>
+#include <QDir>
+
+#include <set>
+
+#include <limits.h>
+#include <stdio.h>
+#include <math.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+#include "xml.h"
+#include "wavecanvas.h"
+#include "event.h"
+#include "globals.h"
+#include "cmd.h"
+#include "song.h"
+#include "audio.h"
+#include "functions.h"
+#include "gconfig.h"
+#include "shortcuts.h"
+#include "editgain.h"
+#include "wave.h"
+#include "waveedit.h"
+#include "fastlog.h"
+#include "utils.h"
+#include "tools.h"
+
+namespace MusEGui {
+
+//---------------------------------------------------------
+// WEvent
+//---------------------------------------------------------
+
+WEvent::WEvent(MusECore::Event& e, MusECore::Part* p, int height) : MusEGui::CItem(e, p)
+ {
+ unsigned frame = e.frame() + p->frame();
+ setPos(QPoint(frame, 0));
+ unsigned len = e.lenFrame();
+ if(e.frame() + e.lenFrame() >= p->lenFrame())
+ len = p->lenFrame() - e.frame();
+ setBBox(QRect(frame, 0, len, height));
+ }
+
+//---------------------------------------------------------
+// addItem
+//---------------------------------------------------------
+
+CItem* WaveCanvas::addItem(MusECore::Part* part, MusECore::Event& event)
+ {
+ if (signed(event.frame())<0) {
+ printf("ERROR: trying to add event before current part!\n");
+ return NULL;
+ }
+
+ WEvent* ev = new WEvent(event, part, height());
+ items.add(ev);
+
+ int diff = event.frame()-part->lenFrame();
+ if (diff > 0) {// too short part? extend it
+ part->setLenFrame(part->lenFrame()+diff);
+ }
+
+ return ev;
+ }
+
+//---------------------------------------------------------
+// WaveCanvas
+//---------------------------------------------------------
+
+WaveCanvas::WaveCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy)
+ : EventCanvas(pr, parent, sx, 1)
+ {
+ colorMode = 0;
+ button = 0;
+
+ editor = pr;
+ setVirt(true);
+
+ setBg(QColor());
+
+ pos[0] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->cpos());
+ pos[1] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->lpos());
+ pos[2] = MusEGlobal::tempomap.tick2frame(MusEGlobal::song->rpos());
+ yScale = sy;
+ mode = NORMAL;
+ selectionStart = 0;
+ selectionStop = 0;
+ lastGainvalue = 100;
+
+ songChanged(SC_TRACK_INSERTED);
+ }
+
+WaveCanvas::~WaveCanvas()
+{
+ //delete steprec;
+}
+
+//---------------------------------------------------------
+// songChanged(type)
+//---------------------------------------------------------
+
+void WaveCanvas::songChanged(MusECore::SongChangedFlags_t flags)
+ {
+ // Is it simply a midi controller value adjustment? Forget it.
+ if(flags == SC_MIDI_CONTROLLER)
+ return;
+
+ if (flags & ~SC_SELECTION) {
+ // TODO FIXME: don't we actually only want SC_PART_*, and maybe SC_TRACK_DELETED?
+ // (same in waveview.cpp)
+ bool curItemNeedsRestore=false;
+ MusECore::Event storedEvent;
+ int partSn;
+ if (curItem)
+ {
+ curItemNeedsRestore=true;
+ storedEvent=curItem->event();
+ partSn=curItem->part()->sn();
+ }
+ curItem=NULL;
+
+ items.clearDelete();
+ startSample = INT_MAX;
+ endSample = 0;
+ curPart = 0;
+ for (MusECore::iPart p = editor->parts()->begin(); p != editor->parts()->end(); ++p) {
+ MusECore::WavePart* part = (MusECore::WavePart*)(p->second);
+ if (part->sn() == curPartId)
+ curPart = part;
+ unsigned ssample = part->frame();
+ unsigned len = part->lenFrame();
+ unsigned esample = ssample + len;
+ if (ssample < startSample)
+ startSample = ssample;
+ if (esample > endSample)
+ endSample = esample;
+
+ MusECore::EventList* el = part->events();
+ for (MusECore::iEvent i = el->begin(); i != el->end(); ++i) {
+ MusECore::Event e = i->second;
+ // Do not add events which are past the end of the part.
+ if(e.frame() > len)
+ break;
+
+ if (e.type() == MusECore::Wave) {
+ CItem* temp = addItem(part, e);
+
+ if (temp && curItemNeedsRestore && e==storedEvent && part->sn()==partSn)
+ {
+ if (curItem!=NULL)
+ printf("THIS SHOULD NEVER HAPPEN: curItemNeedsRestore=true, event fits, but there was already a fitting event!?\n");
+
+ curItem=temp;
+ }
+ }
+ }
+ }
+ }
+
+ MusECore::Event event;
+ MusECore::WavePart* part = 0;
+ int x = 0;
+ CItem* nevent = 0;
+
+ int n = 0; // count selections
+ for (iCItem k = items.begin(); k != items.end(); ++k) {
+ MusECore::Event ev = k->second->event();
+ bool selected = ev.selected();
+ if (selected) {
+ k->second->setSelected(true);
+ ++n;
+ if (!nevent) {
+ nevent = k->second;
+ MusECore::Event mi = nevent->event();
+ }
+ }
+ }
+
+ if (flags & SC_CLIP_MODIFIED) {
+ redraw(); // Boring, but the only thing possible to do
+ }
+ if (flags & SC_TEMPO) {
+ setPos(0, MusEGlobal::song->cpos(), false);
+ setPos(1, MusEGlobal::song->lpos(), false);
+ setPos(2, MusEGlobal::song->rpos(), false);
+ }
+
+ if (n >= 1)
+ {
+ x = nevent->x();
+ event = nevent->event();
+ part = (MusECore::WavePart*)nevent->part();
+ if (_setCurPartIfOnlyOneEventIsSelected && n == 1 && curPart != part) {
+ curPart = part;
+ curPartId = curPart->sn();
+ curPartChanged();
+ }
+ }
+
+ bool f1 = flags & (SC_EVENT_INSERTED | SC_EVENT_MODIFIED | SC_EVENT_REMOVED |
+ SC_PART_INSERTED | SC_PART_MODIFIED | SC_PART_REMOVED |
+ SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED |
+ SC_SIG | SC_TEMPO | SC_KEY | SC_MASTER | SC_CONFIG | SC_DRUMMAP);
+ bool f2 = flags & SC_SELECTION;
+ if(f1 || f2) // Try to avoid all unnecessary emissions.
+ emit selectionChanged(x, event, part, !f1);
+
+ if (curPart == 0)
+ curPart = (MusECore::WavePart*)(editor->parts()->begin()->second);
+ redraw();
+ }
+
+//---------------------------------------------------------
+// selectAtTick
+//---------------------------------------------------------
+
+void WaveCanvas::selectAtTick(unsigned int tick)
+ {
+ selectAtFrame(MusEGlobal::tempomap.tick2frame(tick));
+ }
+
+//---------------------------------------------------------
+// selectAtFrame
+//---------------------------------------------------------
+
+void WaveCanvas::selectAtFrame(unsigned int frame)
+ {
+ //Select event nearest frame, if none selected and there are any
+ if (!items.empty() && selectionSize() == 0) {
+ iCItem i = items.begin();
+ CItem* nearest = i->second;
+
+ while (i != items.end()) {
+ CItem* cur=i->second;
+ unsigned int curf=abs(cur->x() + cur->part()->frame() - frame);
+ unsigned int nearf=abs(nearest->x() + nearest->part()->frame() - frame);
+
+ if (curf < nearf) {
+ nearest=cur;
+ }
+
+ i++;
+ }
+
+ if (!nearest->isSelected()) {
+ selectItem(nearest, true);
+ songChanged(SC_SELECTION);
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// getCaption
+//---------------------------------------------------------
+
+QString WaveCanvas::getCaption() const
+ {
+ int bar1, bar2, xx;
+ unsigned x;
+ AL::sigmap.tickValues(curPart->tick(), &bar1, &xx, &x);
+ AL::sigmap.tickValues(curPart->tick() + curPart->lenTick(), &bar2, &xx, &x);
+
+ return QString("MusE: Part <") + curPart->name()
+ + QString("> %1-%2").arg(bar1+1).arg(bar2+1);
+ }
+
+//---------------------------------------------------------
+// track
+//---------------------------------------------------------
+
+MusECore::WaveTrack* WaveCanvas::track() const
+ {
+ return ((MusECore::WavePart*)curPart)->track();
+ }
+
+
+//---------------------------------------------------------
+// keyPress
+//---------------------------------------------------------
+
+void WaveCanvas::keyPress(QKeyEvent* event)
+ {
+ int key = event->key();
+ if (((QInputEvent*)event)->modifiers() & Qt::ShiftModifier)
+ key += Qt::SHIFT;
+ if (((QInputEvent*)event)->modifiers() & Qt::AltModifier)
+ key += Qt::ALT;
+ if (((QInputEvent*)event)->modifiers() & Qt::ControlModifier)
+ key+= Qt::CTRL;
+
+ // TODO: New WaveCanvas: Convert these to frames, and remove unneeded functions.
+
+ //
+ // Shortcut for DrumEditor & PianoRoll
+ // Sets locators to selected events
+ //
+ if (key == shortcuts[SHRT_LOCATORS_TO_SELECTION].key) {
+ int tick_max = 0;
+ int tick_min = INT_MAX;
+ bool found = false;
+
+ for (iCItem i= items.begin(); i != items.end(); i++) {
+ if (!i->second->isSelected())
+ continue;
+
+ int tick = i->second->x();
+ int len = i->second->event().lenTick();
+ found = true;
+ if (tick + len > tick_max)
+ tick_max = tick + len;
+ if (tick < tick_min)
+ tick_min = tick;
+ }
+ if (found) {
+ MusECore::Pos p1(tick_min, true);
+ MusECore::Pos p2(tick_max, true);
+ MusEGlobal::song->setPos(1, p1);
+ MusEGlobal::song->setPos(2, p2);
+ }
+ }
+ // Select items by key (PianoRoll & DrumEditor)
+ else if (key == shortcuts[SHRT_SEL_RIGHT].key || key == shortcuts[SHRT_SEL_RIGHT_ADD].key) {
+ rciCItem i;
+
+ if (items.empty())
+ return;
+ for (i = items.rbegin(); i != items.rend(); ++i)
+ if (i->second->isSelected())
+ break;
+
+ if(i == items.rend())
+ i = items.rbegin();
+
+ if(i != items.rbegin())
+ --i;
+ if(i->second)
+ {
+ if (key != shortcuts[SHRT_SEL_RIGHT_ADD].key)
+ deselectAll();
+ CItem* sel = i->second;
+ sel->setSelected(true);
+ updateSelection();
+ if (sel->x() + sel->width() > mapxDev(width()))
+ {
+ int mx = rmapx(sel->x());
+ int newx = mx + rmapx(sel->width()) - width();
+ // Leave a bit of room for the specially-drawn drum notes. But good for piano too.
+ emit horizontalScroll( (newx > mx ? mx - 10: newx + 10) - rmapx(xorg) );
+ }
+ }
+ }
+ //Select items by key: (PianoRoll & DrumEditor)
+ else if (key == shortcuts[SHRT_SEL_LEFT].key || key == shortcuts[SHRT_SEL_LEFT_ADD].key) {
+ ciCItem i;
+ if (items.empty())
+ return;
+ for (i = items.begin(); i != items.end(); ++i)
+ if (i->second->isSelected())
+ break;
+
+ if(i == items.end())
+ i = items.begin();
+
+ if(i != items.begin())
+ --i;
+ if(i->second)
+ {
+ if (key != shortcuts[SHRT_SEL_LEFT_ADD].key)
+ deselectAll();
+ CItem* sel = i->second;
+ sel->setSelected(true);
+ updateSelection();
+ if (sel->x() <= mapxDev(0))
+ emit horizontalScroll(rmapx(sel->x() - xorg) - 10); // Leave a bit of room.
+ }
+ }
+ //else if (key == shortcuts[SHRT_INC_PITCH].key) {
+ // modifySelected(NoteInfo::VAL_PITCH, 1);
+ // }
+ //else if (key == shortcuts[SHRT_DEC_PITCH].key) {
+ // modifySelected(NoteInfo::VAL_PITCH, -1);
+ // }
+ else if (key == shortcuts[SHRT_INC_POS].key) {
+ // TODO: Check boundaries
+ modifySelected(NoteInfo::VAL_TIME, editor->raster());
+ }
+ else if (key == shortcuts[SHRT_DEC_POS].key) {
+ // TODO: Check boundaries
+ modifySelected(NoteInfo::VAL_TIME, 0 - editor->raster());
+ }
+
+ else if (key == shortcuts[SHRT_INCREASE_LEN].key) {
+ // TODO: Check boundaries
+ modifySelected(NoteInfo::VAL_LEN, editor->raster());
+ }
+ else if (key == shortcuts[SHRT_DECREASE_LEN].key) {
+ // TODO: Check boundaries
+ modifySelected(NoteInfo::VAL_LEN, 0 - editor->raster());
+ }
+
+ else
+ event->ignore();
+ }
+
+
+//---------------------------------------------------------
+// setPos
+// set one of three markers
+// idx - 0-cpos 1-lpos 2-rpos
+// flag - emit followEvent()
+//---------------------------------------------------------
+
+void WaveCanvas::setPos(int idx, unsigned val, bool adjustScrollbar)
+ {
+ val = MusEGlobal::tempomap.tick2frame(val);
+ if (pos[idx] == val)
+ return;
+ int opos = mapx(pos[idx]);
+ int npos = mapx(val);
+
+ if (adjustScrollbar && idx == 0) {
+ switch (MusEGlobal::song->follow()) {
+ case MusECore::Song::NO:
+ break;
+ case MusECore::Song::JUMP:
+ if (npos >= width()) {
+ int ppos = val - xorg - rmapxDev(width()/4);
+ if (ppos < 0)
+ ppos = 0;
+ emit followEvent(ppos);
+ opos = mapx(pos[idx]);
+ npos = mapx(val);
+ }
+ else if (npos < 0) {
+ int ppos = val - xorg - rmapxDev(width()*3/4);
+ if (ppos < 0)
+ ppos = 0;
+ emit followEvent(ppos);
+ opos = mapx(pos[idx]);
+ npos = mapx(val);
+ }
+ break;
+ case MusECore::Song::CONTINUOUS:
+ if (npos > (width()*5)/8) {
+ int ppos = pos[idx] - xorg - rmapxDev(width()*5/8);
+ if (ppos < 0)
+ ppos = 0;
+ emit followEvent(ppos);
+ opos = mapx(pos[idx]);
+ npos = mapx(val);
+ }
+ else if (npos < (width()*3)/8) {
+ int ppos = pos[idx] - xorg - rmapxDev(width()*3/8);
+ if (ppos < 0)
+ ppos = 0;
+ emit followEvent(ppos);
+ opos = mapx(pos[idx]);
+ npos = mapx(val);
+ }
+ break;
+ }
+ }
+
+ int x;
+ int w = 1;
+ if (opos > npos) {
+ w += opos - npos;
+ x = npos;
+ }
+ else {
+ w += npos - opos;
+ x = opos;
+ }
+ pos[idx] = val;
+ //redraw(QRect(x, 0, w, height()));
+ redraw(QRect(x-1, 0, w+2, height())); // From Canvas::draw (is otherwise identical). Fix for corruption. (TEST: New WaveCanvas: Still true?)
+ }
+
+//---------------------------------------------------------
+// setYScale
+//---------------------------------------------------------
+
+void WaveCanvas::setYScale(int val)
+ {
+ yScale = val;
+ redraw();
+ }
+
+// TODO: Overridden because markers need tick2frame.
+// After BBT/frame mode is added to Canvas, remove this override and let Canvas::draw do it.
+// Also add the drawParts calls to Canvas::draw, and add a dummy Canvas::drawParts { }.
+//---------------------------------------------------------
+// draw
+//---------------------------------------------------------
+
+void WaveCanvas::draw(QPainter& p, const QRect& r)
+ {
+ int x = r.x() < 0 ? 0 : r.x();
+ int y = r.y() < 0 ? 0 : r.y();
+ int w = r.width();
+ int h = r.height();
+ int x2 = x + w;
+
+ std::vector<CItem*> list1;
+ std::vector<CItem*> list2;
+ //std::vector<CItem*> list3;
+ std::vector<CItem*> list4;
+
+ drawCanvas(p, r);
+
+ //---------------------------------------------------
+ // draw Canvas Items
+ //---------------------------------------------------
+
+ iCItem to(items.lower_bound(x2));
+
+ for(iCItem i = items.begin(); i != to; ++i)
+ {
+ CItem* ci = i->second;
+ // NOTE Optimization: For each item call this once now, then use cached results later via cachedHasHiddenEvents().
+ // Not required for now.
+ //ci->part()->hasHiddenEvents();
+
+ // Draw items from other parts behind all others. Only for items with events (not arranger parts).
+ if(!ci->event().empty() && ci->part() != curPart)
+ list1.push_back(ci);
+ else if(!ci->isMoving() && (ci->event().empty() || ci->part() == curPart))
+ {
+ // Draw selected parts in front of all others.
+ if(ci->isSelected())
+ list4.push_back(ci);
+ // Draw clone parts, and parts with hidden events, in front of others all except selected.
+ //else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1 || ci->part()->cachedHasHiddenEvents()))
+ // Draw clone parts in front of others all except selected.
+ //else if(ci->event().empty() && (ci->part()->events()->arefCount() > 1))
+ // list3.push_back(ci);
+ else
+ // Draw unselected parts.
+ list2.push_back(ci);
+ }
+ }
+
+ // Draw non-current part backgrounds behind all others:
+ drawParts(p, r, false);
+
+ int i;
+ int sz = list1.size();
+ for(i = 0; i != sz; ++i)
+ drawItem(p, list1[i], r);
+
+ // Draw current part background in front of all others:
+ drawParts(p, r, true);
+
+ sz = list2.size();
+ for(i = 0; i != sz; ++i)
+ drawItem(p, list2[i], r);
+
+ //sz = list3.size();
+ //for(i = 0; i != sz; ++i)
+ // drawItem(p, list3[i], rect);
+
+ sz = list4.size();
+ for(i = 0; i != sz; ++i)
+ drawItem(p, list4[i], r);
+
+ to = moving.lower_bound(x2);
+ for (iCItem i = moving.begin(); i != to; ++i)
+ {
+ drawItem(p, i->second, r);
+ }
+
+ drawTopItem(p,r);
+
+
+ //---------------------------------------------------
+ // draw marker
+ //---------------------------------------------------
+
+ bool wmtxen = p.worldMatrixEnabled();
+ p.setWorldMatrixEnabled(false);
+
+ int my = mapy(y);
+ int my2 = mapy(y + h);
+
+ MusECore::MarkerList* marker = MusEGlobal::song->marker();
+ for (MusECore::iMarker m = marker->begin(); m != marker->end(); ++m) {
+ int xp = MusEGlobal::tempomap.tick2frame(m->second.tick());
+ if (xp >= x && xp < x2) {
+ p.setPen(Qt::green);
+ p.drawLine(mapx(xp), my, mapx(xp), my2);
+ }
+ }
+
+ //---------------------------------------------------
+ // draw location marker
+ //---------------------------------------------------
+
+ // Tip: These positions are already in units of frames.
+ p.setPen(Qt::blue);
+ int mx;
+ if (pos[1] >= unsigned(x) && pos[1] < unsigned(x2)) {
+ mx = mapx(pos[1]);
+ p.drawLine(mx, my, mx, my2);
+ }
+ if (pos[2] >= unsigned(x) && pos[2] < unsigned(x2)) {
+ mx = mapx(pos[2]);
+ p.drawLine(mx, my, mx, my2);
+ }
+ p.setPen(Qt::red);
+ if (pos[0] >= unsigned(x) && pos[0] < unsigned(x2)) {
+ mx = mapx(pos[0]);
+ p.drawLine(mx, my, mx, my2);
+ }
+
+ //p.restore();
+ //p.setWorldMatrixEnabled(true);
+ p.setWorldMatrixEnabled(wmtxen);
+
+ //---------------------------------------------------
+ // draw lasso
+ //---------------------------------------------------
+
+ if (drag == DRAG_LASSO) {
+ p.setPen(Qt::blue);
+ p.setBrush(Qt::NoBrush);
+ p.drawRect(lasso);
+ }
+
+ //---------------------------------------------------
+ // draw moving items
+ //---------------------------------------------------
+
+ for(iCItem i = moving.begin(); i != moving.end(); ++i)
+ drawMoving(p, i->second, r);
+
+ }
+
+//---------------------------------------------------------
+// drawWaveParts
+//---------------------------------------------------------
+
+void WaveCanvas::drawParts(QPainter& p, const QRect& r, bool do_cur_part)
+{
+ //QRect rr = p.transform().mapRect(r); // Gives inconsistent positions. Source shows wrong operation for our needs.
+ QRect rr = map(r); // Use our own map instead.
+
+ bool wmtxen = p.worldMatrixEnabled();
+ p.setWorldMatrixEnabled(false);
+
+ if(do_cur_part)
+ {
+ // Draw current part:
+ if(curPart)
+ {
+ QRect mwpr = map(QRect(curPart->frame(), 0, curPart->lenFrame(), height()));
+ QRect mpbgr = rr & mwpr;
+ if(!mpbgr.isNull())
+ {
+ QColor c;
+ switch(colorMode)
+ {
+ default:
+ case 0:
+ c = MusEGlobal::config.partColors[curPart->colorIndex()];
+ break;
+ case 1:
+ c = Qt::lightGray;
+ break;
+ }
+ c.setAlpha(MusEGlobal::config.globalAlphaBlend);
+ QBrush part_bg_brush(MusECore::gGradientFromQColor(c, mwpr.topLeft(), mwpr.bottomLeft()));
+ p.fillRect(mpbgr, part_bg_brush);
+ }
+ }
+ }
+ else
+ {
+ // Draw non-current parts:
+ for (MusECore::iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip)
+ {
+ MusECore::WavePart* wp = (MusECore::WavePart*)(ip->second);
+ if(wp == curPart)
+ continue;
+
+ QRect mwpr = map(QRect(wp->frame(), 0, wp->lenFrame(), height()));
+ QRect mpbgr = rr & mwpr;
+ if(!mpbgr.isNull())
+ {
+ //int cidx = wp->colorIndex();
+ //QColor c(MusEGlobal::config.partColors[cidx]);
+ QColor c(Qt::darkGray);
+ c.setAlpha(MusEGlobal::config.globalAlphaBlend);
+ QBrush part_bg_brush(MusECore::gGradientFromQColor(c, mwpr.topLeft(), mwpr.bottomLeft()));
+ p.fillRect(mpbgr, part_bg_brush);
+ }
+ }
+ }
+
+ p.setWorldMatrixEnabled(wmtxen);
+}
+
+// TODO: Overridden because we're in units of frames.
+// After BBT/frame mode is added to Canvas, remove this override and let View or Canvas do it.
+//---------------------------------------------------------
+// drawTickRaster
+//---------------------------------------------------------
+
+void WaveCanvas::drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster)
+ {
+ // Changed to draw in device coordinate space instead of virtual, transformed space. Tim.
+
+ //int mx = mapx(x);
+ int my = mapy(y);
+ //int mw = mapx(x + w) - mx;
+ //int mw = mapx(x + w) - mx - 1;
+ //int mh = mapy(y + h) - my;
+ //int mh = mapy(y + h) - my - 1;
+
+ //p.save();
+ bool wmtxen = p.worldMatrixEnabled();
+ p.setWorldMatrixEnabled(false);
+
+ int xx,bar1, bar2, beat;
+ unsigned tick;
+// AL::sigmap.tickValues(x, &bar1, &beat, &tick);
+// AL::sigmap.tickValues(x+w, &bar2, &beat, &tick);
+ AL::sigmap.tickValues(MusEGlobal::tempomap.frame2tick(x), &bar1, &beat, &tick);
+ AL::sigmap.tickValues(MusEGlobal::tempomap.frame2tick(x+w), &bar2, &beat, &tick);
+ ++bar2;
+ ///int y2 = y + h;
+ //int y2 = my + mh;
+ int y2 = mapy(y + h) - 1;
+ //printf("View::drawTickRaster x:%d y:%d w:%d h:%d mx:%d my:%d mw:%d mh:%d y2:%d bar1:%d bar2:%d\n", x, y, w, h, mx, my, mw, mh, y2, bar1, bar2);
+ //printf("View::drawTickRaster x:%d y:%d w:%d h:%d my:%d mh:%d y2:%d bar1:%d bar2:%d\n", x, y, w, h, my, mh, y2, bar1, bar2);
+ for (int bar = bar1; bar < bar2; ++bar) {
+
+// unsigned xb = AL::sigmap.bar2tick(bar, 0, 0);
+ unsigned xb = AL::sigmap.bar2tick(bar, 0, 0);
+ int xt = mapx(MusEGlobal::tempomap.tick2frame(xb));
+ p.setPen(Qt::black);
+ p.drawLine(xt, my, xt, y2);
+
+ int z, n;
+ AL::sigmap.timesig(xb, z, n);
+ int qq = raster;
+ if (rmapx(raster) < 8) // grid too dense
+ qq *= 2;
+ p.setPen(Qt::lightGray);
+ if (raster>=4) {
+ xx = xb + qq;
+ int xxx = MusEGlobal::tempomap.tick2frame(AL::sigmap.bar2tick(bar, z, 0));
+ //while (MusEGlobal::tempomap.tick2frame(xx) <= xxx) {
+ while (1) {
+ int xxf = MusEGlobal::tempomap.tick2frame(xx);
+ if(xxf > xxx)
+ break;
+ //int x = mapx(MusEGlobal::tempomap.tick2frame(xx));
+ int x = mapx(xxf);
+ p.drawLine(x, my, x, y2);
+ xx += qq;
+ }
+ }
+ p.setPen(Qt::gray);
+ for (int beat = 1; beat < z; beat++) {
+ xx = mapx(MusEGlobal::tempomap.tick2frame(AL::sigmap.bar2tick(bar, beat, 0)));
+ //printf(" bar:%d z:%d beat:%d xx:%d\n", bar, z, beat, xx);
+ p.drawLine(xx, my, xx, y2);
+ }
+
+ }
+ p.setWorldMatrixEnabled(wmtxen);
+ }
+
+// TODO: Overridden because we're in units of frames.
+// After BBT/frame mode is added to Canvas, remove this override and let Canvas do it.
+//---------------------------------------------------------
+// raster
+//---------------------------------------------------------
+
+QPoint WaveCanvas::raster(const QPoint& p) const
+ {
+ int x = p.x();
+ if (x < 0)
+ x = 0;
+ //x = editor->rasterVal(x);
+ x = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x)));
+ int pitch = y2pitch(p.y());
+ int y = pitch2y(pitch);
+ return QPoint(x, y);
+ }
+
+#define WHEEL_STEPSIZE 40
+#define WHEEL_DELTA 120
+//---------------------------------------------------------
+// wheelEvent
+//---------------------------------------------------------
+void WaveCanvas::wheelEvent(QWheelEvent* ev)
+{
+ int keyState = ev->modifiers();
+
+ bool shift = keyState & Qt::ShiftModifier;
+ bool ctrl = keyState & Qt::ControlModifier;
+
+ if (shift) { // scroll vertically
+ int delta = -ev->delta() / WHEEL_DELTA;
+ int xpixelscale = 5*MusECore::fast_log10(rmapxDev(1));
+
+
+ if (xpixelscale <= 0)
+ xpixelscale = 1;
+
+ int scrollstep = WHEEL_STEPSIZE * (delta);
+ ///if (ev->state() == Qt::ShiftModifier)
+ // if (((QInputEvent*)ev)->modifiers() == Qt::ShiftModifier)
+ scrollstep = scrollstep / 10;
+
+ int newXpos = xpos + xpixelscale * scrollstep;
+
+ if (newXpos < 0)
+ newXpos = 0;
+
+ //setYPos(newYpos);
+ emit horizontalScroll((unsigned)newXpos);
+
+
+ } else if (ctrl) { // zoom horizontally
+ if (ev->delta()>0)
+ emit horizontalZoomIn();
+ else
+ emit horizontalZoomOut();
+
+ } else { // scroll horizontally
+ emit mouseWheelMoved(ev->delta() / 10);
+ }
+
+}
+
+//---------------------------------------------------------
+// viewMousePressEvent
+//---------------------------------------------------------
+
+bool WaveCanvas::mousePress(QMouseEvent* event)
+ {
+ if (event->modifiers() & Qt::ControlModifier) {
+ return true;
+ }
+ button = event->button();
+ QPoint pt = event->pos();
+ //CItem* item = items.find(pt);
+ unsigned x = event->x();
+
+ switch (_tool) {
+ default:
+ break;
+ case CursorTool:
+ switch (button) {
+ case Qt::LeftButton:
+ if (mode == NORMAL) {
+ // redraw and reset:
+ if (selectionStart != selectionStop) {
+ selectionStart = selectionStop = 0;
+ redraw();
+ }
+ mode = DRAG;
+ dragstartx = x;
+ selectionStart = selectionStop = x;
+ drag = DRAG_LASSO_START;
+ Canvas::start = pt;
+ return false;
+ }
+ break;
+
+ case Qt::MidButton:
+ case Qt::RightButton:
+ default:
+ break;
+ }
+
+ break;
+ }
+ return true;
+ }
+
+//---------------------------------------------------------
+// viewMouseReleaseEvent
+//---------------------------------------------------------
+
+void WaveCanvas::mouseRelease(const QPoint&)
+ {
+ button = Qt::NoButton;
+ if (mode == DRAG) {
+ mode = NORMAL;
+ }
+ }
+
+//---------------------------------------------------------
+// viewMousevent
+//---------------------------------------------------------
+
+void WaveCanvas::mouseMove(QMouseEvent* event)
+ {
+ int x = event->x();
+ if (x < 0)
+ x = 0;
+ emit timeChanged(x);
+ //emit timeChanged(editor->rasterVal(x));
+ //emit timeChanged(AL::sigmap.raster(x, *_raster));
+
+ switch (button) {
+ case Qt::LeftButton:
+ if (mode == DRAG) {
+ int mx = mapx(x);
+ int mstart = mapx(selectionStart);
+ int mstop = mapx(selectionStop);
+ //int mdstart = mapx(dragstartx);
+ QRect r(0, 0, 0, height());
+
+ if (x < dragstartx) {
+ if(x < selectionStart)
+ {
+ r.setLeft(mx);
+ r.setWidth((selectionStop >= dragstartx ? mstop : mstart) - mx);
+ }
+ else
+ {
+ r.setLeft(mstart);
+ r.setWidth(mx - mstart);
+ }
+ selectionStart = x;
+ selectionStop = dragstartx;
+ }
+ else {
+ if(x >= selectionStop)
+ {
+ r.setLeft(selectionStart < dragstartx ? mstart : mstop);
+ r.setWidth(mx - (selectionStart < dragstartx ? mstart : mstop));
+ }
+ else
+ {
+ r.setLeft(mx);
+ r.setWidth(mstop - mx);
+ }
+ selectionStart = dragstartx;
+ selectionStop = x;
+ }
+ update(r);
+ }
+ break;
+ case Qt::MidButton:
+ break;
+ case Qt::RightButton:
+ break;
+ default:
+ return;
+ }
+ }
+
+//---------------------------------------------------------
+// pitch2y
+//---------------------------------------------------------
+
+int WaveCanvas::pitch2y(int) const
+ {
+ return 0;
+ }
+
+//---------------------------------------------------------
+// y2pitch
+//---------------------------------------------------------
+
+int WaveCanvas::y2pitch(int) const
+ {
+ return 0;
+ }
+
+//---------------------------------------------------------
+// drawItem
+// draws a wave
+//---------------------------------------------------------
+
+void WaveCanvas::drawItem(QPainter& p, const MusEGui::CItem* item, const QRect& rect)
+{
+ MusECore::WavePart* wp = (MusECore::WavePart*)(item->part());
+ if(!wp || !wp->track())
+ return;
+
+ //QRect rr = p.transform().mapRect(rect); // Gives inconsistent positions. Source shows wrong operation for our needs.
+ QRect rr = map(rect); // Use our own map instead.
+
+ QRect mwpr = map(QRect(wp->frame(), 0, wp->lenFrame(), height()));
+
+ QRect r = item->bbox();
+ QRect mer = map(r);
+ QRect mr = rr & mer & mwpr;
+ if(mr.isNull())
+ return;
+
+ MusECore::Event event = item->event();
+ if(event.empty())
+ return;
+
+ int x1 = mr.x();
+ int x2 = mr.right() + 1;
+ if (x1 < 0)
+ x1 = 0;
+ if (x2 > width())
+ x2 = width();
+ int hh = height();
+ int h = hh/2;
+ int y = mr.y() + h;
+
+ int xScale = xmag;
+ if (xScale < 0)
+ xScale = -xScale;
+
+ //int t_channels = wp->track()->channels();
+ int px = wp->frame();
+
+ bool wmtxen = p.worldMatrixEnabled();
+ p.setWorldMatrixEnabled(false);
+
+ int sx, ex;
+
+ sx = event.frame() + px + xScale/2;
+ ex = sx + event.lenFrame();
+ sx = sx / xScale - xpos;
+ ex = ex / xScale - xpos;
+
+ if (sx < x1)
+ sx = x1;
+ if (ex > x2)
+ ex = x2;
+
+ int pos = (xpos + sx) * xScale + event.spos() - event.frame() - px;
+
+ //printf("pos=%d xpos=%d sx=%d ex=%d xScale=%d event.spos=%d event.frame=%d px=%d\n",
+ // pos, xpos, sx, ex, xScale, event.spos(), event.frame(), px);
+
+
+ QBrush brush;
+ if (item->isMoving())
+ {
+ QColor c(Qt::gray);
+ c.setAlpha(MusEGlobal::config.globalAlphaBlend);
+ QLinearGradient gradient(r.topLeft(), r.bottomLeft());
+ gradient.setColorAt(0, c);
+ gradient.setColorAt(1, c.darker());
+ brush = QBrush(gradient);
+ p.fillRect(sx, 0, ex - sx, hh, brush);
+ }
+ else
+ if (item->isSelected())
+ {
+ QColor c(Qt::black);
+ c.setAlpha(MusEGlobal::config.globalAlphaBlend);
+ QLinearGradient gradient(r.topLeft(), r.bottomLeft());
+ // Use a colour only about 20% lighter than black, rather than the 50% we use in MusECore::gGradientFromQColor
+ // and is used in darker()/lighter(), so that it is distinguished a bit better from grey non-part tracks.
+ //c.setRgba(64, 64, 64, c.alpha());
+ gradient.setColorAt(0, QColor(51, 51, 51, MusEGlobal::config.globalAlphaBlend));
+ gradient.setColorAt(1, c);
+ brush = QBrush(gradient);
+ p.fillRect(sx, 0, ex - sx, hh, brush);
+ }
+ //else
+ {
+ QPen pen(Qt::DashLine);
+ pen.setColor(Qt::black);
+ pen.setCosmetic(true);
+ p.setPen(pen);
+ p.drawRect(sx, 0, ex - sx, hh);
+ }
+ //p.fillRect(sx, 0, ex - sx, hh, brush);
+ //p.drawRect(sx, 0, ex - sx, hh, brush);
+
+ MusECore::SndFileR f = event.sndFile();
+ if(f.isNull())
+ {
+ p.setWorldMatrixEnabled(wmtxen);
+ return;
+ }
+
+ int ev_channels = f.channels();
+ if (ev_channels == 0) {
+ p.setWorldMatrixEnabled(wmtxen);
+ printf("WaveCnvas::drawItem: ev_channels==0! %s\n", f.name().toLatin1().constData());
+ return;
+ }
+
+ h = hh / (ev_channels * 2);
+ int cc = hh % (ev_channels * 2) ? 0 : 1;
+
+ unsigned peoffset = px + event.frame() - event.spos();
+
+ for (int i = sx; i < ex; i++) {
+ y = mr.y() + h;
+ MusECore::SampleV sa[f.channels()];
+ f.read(sa, xScale, pos);
+ pos += xScale;
+ if (pos < event.spos())
+ continue;
+
+ int selectionStartPos = selectionStart - peoffset; // Offset transformed to event coords
+ int selectionStopPos = selectionStop - peoffset;
+
+ for (int k = 0; k < ev_channels; ++k) {
+ int kk = k % f.channels();
+ int peak = (sa[kk].peak * (h - 1)) / yScale;
+ int rms = (sa[kk].rms * (h - 1)) / yScale;
+ if (peak > h)
+ peak = h;
+ if (rms > h)
+ rms = h;
+ QColor peak_color = QColor(Qt::darkGray);
+ QColor rms_color = QColor(Qt::black);
+
+ // Changed by T356. Reduces (but not eliminates) drawing artifacts. (TODO Cause of artifacts gone, correct this now.)
+ //if (pos > selectionStartPos && pos < selectionStopPos) {
+ if (pos > selectionStartPos && pos <= selectionStopPos) {
+
+ peak_color = QColor(Qt::lightGray);
+ rms_color = QColor(Qt::white);
+ // Draw inverted
+ p.setPen(QColor(Qt::black));
+ p.drawLine(i, y - h + cc, i, y + h - cc );
+ }
+ p.setPen(peak_color);
+ p.drawLine(i, y - peak - cc, i, y + peak);
+ p.setPen(rms_color);
+ p.drawLine(i, y - rms - cc, i, y + rms);
+ y += 2 * h;
+ }
+ }
+
+
+ int hn = hh / ev_channels;
+ int hhn = hn / 2;
+ for (int i = 0; i < ev_channels; ++i) {
+ int h2 = hn * i;
+ int center = hhn + h2;
+ p.setPen(QColor(i & i ? Qt::red : Qt::blue));
+ p.drawLine(sx, center, ex, center);
+ p.setPen(QColor(Qt::black));
+ p.drawLine(sx, h2, ex, h2);
+ }
+
+ p.setWorldMatrixEnabled(wmtxen);
+}
+
+//---------------------------------------------------------
+// drawTopItem
+//---------------------------------------------------------
+void WaveCanvas::drawTopItem(QPainter& , const QRect&)
+{}
+
+//---------------------------------------------------------
+// drawMoving
+// draws moving items
+//---------------------------------------------------------
+
+void WaveCanvas::drawMoving(QPainter& p, const MusEGui::CItem* item, const QRect& rect)
+ {
+ QRect mr = QRect(item->mp().x(), item->mp().y(), item->width(), item->height());
+ mr = mr.intersected(rect);
+ if(!mr.isValid())
+ return;
+ p.setPen(Qt::black);
+ p.setBrush(QColor(0, 128, 0, 128)); // TODO: Pick a better colour, or use part colours, or grey?
+ p.drawRect(mr);
+ }
+
+//---------------------------------------------------------
+// viewMouseDoubleClickEvent
+//---------------------------------------------------------
+
+void WaveCanvas::viewMouseDoubleClickEvent(QMouseEvent* event)
+ {
+ if ((_tool != MusEGui::PointerTool) && (event->button() != Qt::LeftButton)) {
+ mousePress(event);
+ return;
+ }
+ }
+
+//---------------------------------------------------------
+// moveCanvasItems
+//---------------------------------------------------------
+
+MusECore::Undo WaveCanvas::moveCanvasItems(MusEGui::CItemList& items, int /*dp*/, int dx, DragType dtype)
+{
+ if(editor->parts()->empty())
+ return MusECore::Undo(); //return empty list
+
+ MusECore::PartsToChangeMap parts2change;
+ MusECore::Undo operations;
+
+ for(MusECore::iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip)
+ {
+ MusECore::Part* part = ip->second;
+ if(!part)
+ continue;
+
+ int npartoffset = 0;
+ for(MusEGui::iCItem ici = items.begin(); ici != items.end(); ++ici)
+ {
+ MusEGui::CItem* ci = ici->second;
+ if(ci->part() != part)
+ continue;
+
+ int x = ci->pos().x() + dx;
+ //int y = pitch2y(y2pitch(ci->pos().y()) + dp);
+ int y = 0;
+ QPoint newpos = raster(QPoint(x, y));
+
+ // Test moving the item...
+ WEvent* wevent = (WEvent*) ci;
+ MusECore::Event event = wevent->event();
+ x = newpos.x();
+ if(x < 0)
+ x = 0;
+ int nframe = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x))) - part->frame();
+ if(nframe < 0)
+ nframe = 0;
+ int diff = nframe + event.lenFrame() - part->lenFrame();
+
+ // If moving the item would require a new part size...
+ if(diff > npartoffset)
+ npartoffset = diff;
+ }
+
+ if(npartoffset > 0)
+ {
+ MusECore::iPartToChange ip2c = parts2change.find(part);
+ if(ip2c == parts2change.end())
+ {
+ MusECore::PartToChange p2c = {0, npartoffset};
+ parts2change.insert(std::pair<MusECore::Part*, MusECore::PartToChange> (part, p2c));
+ }
+ else
+ ip2c->second.xdiff = npartoffset;
+ }
+ }
+
+ bool forbidden=false;
+ for(MusECore::iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c)
+ {
+ MusECore::Part* opart = ip2c->first;
+ if (opart->hasHiddenEvents())
+ {
+ forbidden=true;
+ break;
+ }
+ }
+
+
+ if (!forbidden)
+ {
+ std::vector< MusEGui::CItem* > doneList;
+ typedef std::vector< MusEGui::CItem* >::iterator iDoneList;
+
+ for(MusEGui::iCItem ici = items.begin(); ici != items.end(); ++ici)
+ {
+ MusEGui::CItem* ci = ici->second;
+
+ int x = ci->pos().x();
+ //int y = ci->pos().y();
+ int nx = x + dx;
+ //int ny = pitch2y(y2pitch(y) + dp);
+ int ny = 0;
+ QPoint newpos = raster(QPoint(nx, ny));
+ selectItem(ci, true);
+
+ iDoneList idl;
+ for(idl = doneList.begin(); idl != doneList.end(); ++idl)
+ // This compares EventBase pointers to see if they're the same...
+ if((*idl)->event() == ci->event())
+ break;
+
+ // Do not process if the event has already been processed (meaning it's an event in a clone part)...
+ if (idl == doneList.end())
+ {
+ moveItem(operations, ci, newpos, dtype); // always returns true. if not, change is necessary here!
+ doneList.push_back(ci);
+ }
+ ci->move(newpos);
+
+ if(moving.size() == 1)
+ itemReleased(curItem, newpos);
+
+ if(dtype == MOVE_COPY || dtype == MOVE_CLONE)
+ selectItem(ci, false);
+ }
+
+ for(MusECore::iPartToChange ip2c = parts2change.begin(); ip2c != parts2change.end(); ++ip2c)
+ {
+ MusECore::Part* opart = ip2c->first;
+ int diff = ip2c->second.xdiff;
+
+ //schedule_resize_all_same_len_clone_parts(opart, opart->lenTick() + diff, operations);
+ schedule_resize_all_same_len_clone_parts(opart, opart->lenFrame() + diff, operations);
+ }
+
+ return operations;
+ }
+ else
+ {
+ return MusECore::Undo(); //return empty list
+ }
+}
+
+//---------------------------------------------------------
+// moveItem
+// called after moving an object
+//---------------------------------------------------------
+
+bool WaveCanvas::moveItem(MusECore::Undo& operations, MusEGui::CItem* item, const QPoint& pos, DragType dtype)
+ {
+ WEvent* wevent = (WEvent*) item;
+ MusECore::Event event = wevent->event();
+ //int npitch = y2pitch(pos.y());
+ MusECore::Event newEvent = event.clone();
+ int x = pos.x();
+ if (x < 0)
+ x = 0;
+
+ MusECore::Part* part = wevent->part();
+ int nframe = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x))) - part->frame();
+ if (nframe < 0)
+ nframe = 0;
+ newEvent.setFrame(nframe);
+ newEvent.setLenFrame(event.lenFrame());
+
+ // don't check, whether the new event is within the part
+ // at this place. with operation groups, the part isn't
+ // resized yet. (flo93)
+
+ if (dtype == MOVE_COPY || dtype == MOVE_CLONE)
+ operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddEvent, newEvent, part, false, false));
+ else
+ operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
+
+ return true;
+}
+
+//---------------------------------------------------------
+// newItem(p, state)
+//---------------------------------------------------------
+
+MusEGui::CItem* WaveCanvas::newItem(const QPoint& p, int)
+ {
+ int frame = MusEGlobal::tempomap.tick2frame(editor->rasterVal1(MusEGlobal::tempomap.frame2tick(p.x())));
+ int len = p.x() - frame;
+ frame -= curPart->frame();
+ if (frame < 0)
+ return 0;
+ MusECore::Event e = MusECore::Event(MusECore::Wave);
+ e.setFrame(frame);
+ e.setLenFrame(len);
+ WEvent* we = new WEvent(e, curPart, height());
+ return we;
+ }
+
+void WaveCanvas::newItem(MusEGui::CItem* item, bool noSnap)
+ {
+ WEvent* wevent = (WEvent*) item;
+ MusECore::Event event = wevent->event();
+ int x = item->x();
+ if (x<0)
+ x=0;
+ int w = item->width();
+
+ if (!noSnap) {
+ //x = editor->rasterVal1(x); //round down
+ x = MusEGlobal::tempomap.tick2frame(editor->rasterVal1(MusEGlobal::tempomap.frame2tick(x))); //round down
+ //w = editor->rasterVal(x + w) - x;
+ w = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(x + w))) - x;
+ if (w == 0)
+ //w = editor->raster();
+ w = MusEGlobal::tempomap.tick2frame(editor->raster());
+ }
+ MusECore::Part* part = wevent->part();
+ event.setFrame(x - part->frame());
+ event.setLenFrame(w);
+
+ MusECore::Undo operations;
+ int diff = event.endFrame() - part->lenFrame();
+
+ if (! ((diff > 0) && part->hasHiddenEvents()) ) //operation is allowed
+ {
+ operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddEvent,event, part, false, false));
+
+ if (diff > 0)// part must be extended?
+ {
+ //schedule_resize_all_same_len_clone_parts(part, event.endTick(), operations);
+ schedule_resize_all_same_len_clone_parts(part, event.endFrame(), operations);
+ printf("newItem: extending\n");
+ }
+
+ MusEGlobal::song->applyOperationGroup(operations);
+ }
+ else // forbid action by not applying it
+ songChanged(SC_EVENT_INSERTED); //this forces an update of the itemlist, which is neccessary
+ //to remove "forbidden" events from the list again
+ }
+
+//---------------------------------------------------------
+// resizeItem
+//---------------------------------------------------------
+
+void WaveCanvas::resizeItem(MusEGui::CItem* item, bool noSnap, bool) // experimental changes to try dynamically extending parts
+ {
+ WEvent* wevent = (WEvent*) item;
+ MusECore::Event event = wevent->event();
+ MusECore::Event newEvent = event.clone();
+ int len;
+
+ MusECore::Part* part = wevent->part();
+
+ if (noSnap)
+ len = wevent->width();
+ else {
+ unsigned frame = event.frame() + part->frame();
+ //len = editor->rasterVal(tick + wevent->width()) - tick;
+ len = MusEGlobal::tempomap.tick2frame(editor->rasterVal(MusEGlobal::tempomap.frame2tick(frame + wevent->width()))) - frame;
+ if (len <= 0)
+ //len = editor->raster();
+ len = MusEGlobal::tempomap.tick2frame(editor->raster());
+ }
+
+ MusECore::Undo operations;
+ //int diff = event.tick()+len-part->lenTick();
+ int diff = event.frame() + len - part->lenFrame();
+
+ if (! ((diff > 0) && part->hasHiddenEvents()) ) //operation is allowed
+ {
+ //newEvent.setLenTick(len);
+ newEvent.setLenFrame(len);
+ operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent,newEvent, event, wevent->part(), false, false));
+
+ if (diff > 0)// part must be extended?
+ {
+ //schedule_resize_all_same_len_clone_parts(part, event.tick()+len, operations);
+ schedule_resize_all_same_len_clone_parts(part, event.frame() + len, operations);
+ printf("resizeItem: extending\n");
+ }
+ }
+ //else forbid action by not performing it
+ MusEGlobal::song->applyOperationGroup(operations);
+ songChanged(SC_EVENT_MODIFIED); //this forces an update of the itemlist, which is neccessary
+ //to remove "forbidden" events from the list again
+ }
+
+//---------------------------------------------------------
+// deleteItem
+//---------------------------------------------------------
+
+bool WaveCanvas::deleteItem(MusEGui::CItem* item)
+ {
+ WEvent* wevent = (WEvent*) item;
+ if (wevent->part() == curPart) {
+ MusECore::Event ev = wevent->event();
+ // Indicate do undo, and do not do port controller values and clone parts.
+ MusEGlobal::audio->msgDeleteEvent(ev, curPart, true, false, false);
+ return true;
+ }
+ return false;
+ }
+
+//---------------------------------------------------------
+// draw
+//---------------------------------------------------------
+
+void WaveCanvas::drawCanvas(QPainter& p, const QRect& rect)
+ {
+ int x = rect.x();
+ int y = rect.y();
+ int w = rect.width();
+ int h = rect.height();
+
+ //---------------------------------------------------
+ // vertical lines
+ //---------------------------------------------------
+
+ drawTickRaster(p, x, y, w, h, editor->raster());
+ }
+
+//---------------------------------------------------------
+// waveCmd
+//---------------------------------------------------------
+
+void WaveCanvas::waveCmd(int cmd)
+ {
+ // TODO: New WaveCanvas: Convert this routine to frames.
+ switch(cmd) {
+ case CMD_LEFT:
+ {
+ int spos = pos[0];
+ if(spos > 0)
+ {
+ spos -= 1; // Nudge by -1, then snap down with raster1.
+ spos = AL::sigmap.raster1(spos, editor->rasterStep(pos[0]));
+ }
+ if(spos < 0)
+ spos = 0;
+ MusECore::Pos p(spos,true);
+ MusEGlobal::song->setPos(0, p, true, true, true);
+ }
+ break;
+ case CMD_RIGHT:
+ {
+ int spos = AL::sigmap.raster2(pos[0] + 1, editor->rasterStep(pos[0])); // Nudge by +1, then snap up with raster2.
+ MusECore::Pos p(spos,true);
+ MusEGlobal::song->setPos(0, p, true, true, true);
+ }
+ break;
+ case CMD_LEFT_NOSNAP:
+ {
+ int spos = pos[0] - editor->rasterStep(pos[0]);
+ if (spos < 0)
+ spos = 0;
+ MusECore::Pos p(spos,true);
+ MusEGlobal::song->setPos(0, p, true, true, true); //CDW
+ }
+ break;
+ case CMD_RIGHT_NOSNAP:
+ {
+ MusECore::Pos p(pos[0] + editor->rasterStep(pos[0]), true);
+ MusEGlobal::song->setPos(0, p, true, true, true); //CDW
+ }
+ break;
+ case CMD_INSERT:
+ {
+ if (pos[0] < start() || pos[0] >= end())
+ break;
+ MusECore::MidiPart* part = (MusECore::MidiPart*)curPart;
+
+ if (part == 0)
+ break;
+
+ MusECore::EventList* el = part->events();
+ MusECore::Undo operations;
+
+ std::list <MusECore::Event> elist;
+ for (MusECore::iEvent e = el->lower_bound(pos[0] - part->tick()); e != el->end(); ++e)
+ elist.push_back((MusECore::Event)e->second);
+ for (std::list<MusECore::Event>::iterator i = elist.begin(); i != elist.end(); ++i) {
+ MusECore::Event event = *i;
+ MusECore::Event newEvent = event.clone();
+ newEvent.setTick(event.tick() + editor->raster());// - part->tick()); DELETETHIS
+ // Do not do port controller values and clone parts.
+ operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
+ }
+ MusEGlobal::song->applyOperationGroup(operations);
+
+ MusECore::Pos p(editor->rasterVal(pos[0] + editor->rasterStep(pos[0])), true);
+ MusEGlobal::song->setPos(0, p, true, false, true);
+ }
+ return;
+ case CMD_BACKSPACE:
+ if (pos[0] < start() || pos[0] >= end())
+ break;
+ {
+ MusECore::MidiPart* part = (MusECore::MidiPart*)curPart;
+ if (part == 0)
+ break;
+
+ MusECore::Undo operations;
+ MusECore::EventList* el = part->events();
+
+ std::list<MusECore::Event> elist;
+ for (MusECore::iEvent e = el->lower_bound(pos[0]); e != el->end(); ++e)
+ elist.push_back((MusECore::Event)e->second);
+ for (std::list<MusECore::Event>::iterator i = elist.begin(); i != elist.end(); ++i) {
+ MusECore::Event event = *i;
+ MusECore::Event newEvent = event.clone();
+ newEvent.setTick(event.tick() - editor->raster() - part->tick());
+ // Do not do port controller values and clone parts.
+ operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
+ }
+ MusEGlobal::song->applyOperationGroup(operations);
+ MusECore::Pos p(editor->rasterVal(pos[0] - editor->rasterStep(pos[0])), true);
+ MusEGlobal::song->setPos(0, p, true, false, true);
+ }
+ break;
+ }
+ }
+
+//---------------------------------------------------------
+// cmd
+// pulldown menu commands
+//---------------------------------------------------------
+
+void WaveCanvas::cmd(int cmd)
+ {
+ int modifyoperation = -1;
+ double paramA = 0.0;
+ switch (cmd) {
+ case CMD_SELECT_ALL: // select all
+ if (tool() == MusEGui::CursorTool)
+ {
+ if (!editor->parts()->empty()) {
+ MusECore::iPart iBeg = editor->parts()->begin();
+ MusECore::iPart iEnd = editor->parts()->end();
+ iEnd--;
+ MusECore::WavePart* beg = (MusECore::WavePart*) iBeg->second;
+ MusECore::WavePart* end = (MusECore::WavePart*) iEnd->second;
+ selectionStart = beg->frame();
+ selectionStop = end->frame() + end->lenFrame();
+ redraw();
+ }
+ }
+ for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
+ if (!k->second->isSelected())
+ selectItem(k->second, true);
+ }
+ break;
+ case CMD_SELECT_NONE: // select none
+ selectionStart = selectionStop = 0;
+ deselectAll();
+ break;
+ case CMD_SELECT_INVERT: // invert selection
+ for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
+ selectItem(k->second, !k->second->isSelected());
+ }
+ break;
+ case CMD_SELECT_ILOOP: // select inside loop
+ for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
+ WEvent* wevent = (WEvent*)(k->second);
+ MusECore::Part* part = wevent->part();
+ MusECore::Event event = wevent->event();
+ unsigned tick = event.tick() + part->tick();
+ if (tick < MusEGlobal::song->lpos() || tick >= MusEGlobal::song->rpos())
+ selectItem(k->second, false);
+ else
+ selectItem(k->second, true);
+ }
+ break;
+ case CMD_SELECT_OLOOP: // select outside loop
+ for (MusEGui::iCItem k = items.begin(); k != items.end(); ++k) {
+ WEvent* wevent = (WEvent*)(k->second);
+ MusECore::Part* part = wevent->part();
+ MusECore::Event event = wevent->event();
+ unsigned tick = event.tick() + part->tick();
+ if (tick < MusEGlobal::song->lpos() || tick >= MusEGlobal::song->rpos())
+ selectItem(k->second, true);
+ else
+ selectItem(k->second, false);
+ }
+ break;
+ case CMD_SELECT_PREV_PART: // select previous part
+ {
+ MusECore::Part* pt = editor->curCanvasPart();
+ MusECore::Part* newpt = pt;
+ MusECore::PartList* pl = editor->parts();
+ for(MusECore::iPart ip = pl->begin(); ip != pl->end(); ++ip)
+ if(ip->second == pt)
+ {
+ if(ip == pl->begin())
+ ip = pl->end();
+ --ip;
+ newpt = ip->second;
+ break;
+ }
+ if(newpt != pt)
+ editor->setCurCanvasPart(newpt);
+ }
+ break;
+ case CMD_SELECT_NEXT_PART: // select next part
+ {
+ MusECore::Part* pt = editor->curCanvasPart();
+ MusECore::Part* newpt = pt;
+ MusECore::PartList* pl = editor->parts();
+ for(MusECore::iPart ip = pl->begin(); ip != pl->end(); ++ip)
+ if(ip->second == pt)
+ {
+ ++ip;
+ if(ip == pl->end())
+ ip = pl->begin();
+ newpt = ip->second;
+ break;
+ }
+ if(newpt != pt)
+ editor->setCurCanvasPart(newpt);
+ }
+ break;
+
+
+ case CMD_EDIT_EXTERNAL:
+ modifyoperation = EDIT_EXTERNAL;
+ break;
+
+ case CMD_EDIT_COPY:
+ modifyoperation = COPY;
+ break;
+ case CMD_EDIT_CUT:
+ modifyoperation = CUT;
+ break;
+ case CMD_EDIT_PASTE:
+ modifyoperation = PASTE;
+ break;
+
+ case CMD_MUTE:
+ modifyoperation = MUTE;
+ break;
+
+ case CMD_NORMALIZE:
+ modifyoperation = NORMALIZE;
+ break;
+
+ case CMD_FADE_IN:
+ modifyoperation = FADE_IN;
+ break;
+
+ case CMD_FADE_OUT:
+ modifyoperation = FADE_OUT;
+ break;
+
+ case CMD_REVERSE:
+ modifyoperation = REVERSE;
+ break;
+
+ case 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;
+ }
+ break;
+
+ case CMD_GAIN_200:
+ modifyoperation = GAIN;
+ paramA = 2.0;
+ break;
+
+ case CMD_GAIN_150:
+ modifyoperation = GAIN;
+ paramA = 1.5;
+ break;
+
+ case CMD_GAIN_75:
+ modifyoperation = GAIN;
+ paramA = 0.75;
+ break;
+
+ case CMD_GAIN_50:
+ modifyoperation = GAIN;
+ paramA = 0.5;
+ break;
+
+ case CMD_GAIN_25:
+ modifyoperation = GAIN;
+ paramA = 0.25;
+ break;
+
+
+
+ case CMD_ERASE_MEASURE:
+ case CMD_DELETE_MEASURE:
+ case CMD_CREATE_MEASURE:
+ break;
+ default:
+// printf("unknown ecanvas cmd %d\n", cmd);
+ break;
+ }
+
+ if (modifyoperation != -1) {
+ if (selectionStart == selectionStop && modifyoperation!=PASTE) {
+ printf("No selection. Ignoring\n"); //@!TODO: Disable menu options when no selection
+ QMessageBox::information(this,
+ QString("MusE"),
+ QWidget::tr("No selection. Ignoring"));
+
+ return;
+ }
+
+ //if(!modifyWarnedYet)
+ //{
+ // modifyWarnedYet = true;
+ // if(QMessageBox::warning(this, QString("Muse"),
+ // tr("Warning! Muse currently operates directly on the sound file.\n"
+ // "Undo is supported, but NOT after exit, WITH OR WITHOUT A SAVE!\n"
+ // "If you are stuck, try deleting the associated .wca file and reloading."), tr("&Ok"), tr("&Cancel"),
+ // QString::null, 0, 1 ) != 0)
+ // return;
+ //}
+ modifySelection(modifyoperation, selectionStart, selectionStop, paramA);
+ }
+
+ updateSelection();
+ redraw();
+ }
+
+//---------------------------------------------------------
+// getSelection
+//---------------------------------------------------------
+MusECore::WaveSelectionList WaveCanvas::getSelection(unsigned startpos, unsigned stoppos)
+ {
+ MusECore::WaveSelectionList selection;
+
+ for (MusECore::iPart ip = editor->parts()->begin(); ip != editor->parts()->end(); ++ip) {
+ MusECore::WavePart* wp = (MusECore::WavePart*)(ip->second);
+ unsigned part_offset = wp->frame();
+
+ MusECore::EventList* el = wp->events();
+ //printf("eventlist length=%d\n",el->size());
+
+ for (MusECore::iEvent e = el->begin(); e != el->end(); ++e) {
+ MusECore::Event event = e->second;
+ if (event.empty())
+ continue;
+ MusECore::SndFileR file = event.sndFile();
+ if (file.isNull())
+ continue;
+
+ // Respect part end: Don't modify stuff outside of part boundary.
+ unsigned elen = event.lenFrame();
+ if(event.frame() + event.lenFrame() >= wp->lenFrame())
+ {
+ // Adjust apparent operation length:
+ if(event.frame() > wp->lenFrame())
+ elen = 0;
+ else
+ elen = wp->lenFrame() - event.frame();
+ }
+
+ unsigned event_offset = event.frame() + part_offset;
+ unsigned event_startpos = event.spos();
+ unsigned event_length = elen + 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().constData());
+ MusECore::WaveEventSelection s;
+ s.file = file;
+ s.startframe = sx;
+ s.endframe = ex+1;
+ //printf("sx=%d ex=%d\n",sx,ex);
+ selection.push_back(s);
+ }
+ }
+ }
+
+ return selection;
+ }
+
+//---------------------------------------------------------
+// modifySelection
+//---------------------------------------------------------
+void WaveCanvas::modifySelection(int operation, unsigned startpos, unsigned stoppos, double paramA)
+ {
+ MusEGlobal::song->startUndo();
+
+ if (operation == PASTE) {
+ // we need to redefine startpos and stoppos
+ if (copiedPart =="")
+ return;
+ MusECore::SndFile pasteFile(copiedPart);
+ pasteFile.openRead();
+ startpos = pos[0];
+ stoppos = startpos+ pasteFile.samples(); // possibly this is wrong if there are tempo changes
+ pasteFile.close();
+ pos[0]=stoppos;
+ }
+
+ MusECore::WaveSelectionList selection = getSelection(startpos, stoppos);
+ for (MusECore::iWaveSelection i = selection.begin(); i != selection.end(); i++) {
+ MusECore::WaveEventSelection w = *i;
+ MusECore::SndFileR& file = w.file;
+ unsigned sx = w.startframe;
+ unsigned ex = w.endframe;
+ unsigned file_channels = file.channels();
+
+ QString tmpWavFile = QString::null;
+ if (!MusEGlobal::getUniqueTmpfileName("tmp_musewav",".wav", tmpWavFile)) {
+ break;
+ }
+
+ MusEGlobal::audio->msgIdle(true); // Not good with playback during operations
+ MusECore::SndFile tmpFile(tmpWavFile);
+ tmpFile.setFormat(file.format(), file_channels, file.samplerate());
+ if (tmpFile.openWrite()) {
+ MusEGlobal::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.readWithHeap(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 CUT:
+ copySelection(file_channels, tmpdata, tmpdatalen, true, file.format(), file.samplerate());
+ break;
+ case COPY:
+ copySelection(file_channels, tmpdata, tmpdatalen, false, file.format(), file.samplerate());
+ break;
+ case PASTE:
+ {
+ MusECore::SndFile pasteFile(copiedPart);
+ pasteFile.openRead();
+ pasteFile.seek(tmpdataoffset, 0);
+ pasteFile.readWithHeap(file_channels, tmpdata, tmpdatalen);
+ }
+ 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
+ MusEGlobal::song->cmdChangeWave(file.dirPath() + "/" + file.name(), tmpWavFile, sx, ex);
+ MusEGlobal::audio->msgIdle(false); // Not good with playback during operations
+ }
+ MusEGlobal::song->endUndo(SC_CLIP_MODIFIED);
+ redraw();
+ }
+
+//---------------------------------------------------------
+// copySelection
+//---------------------------------------------------------
+void WaveCanvas::copySelection(unsigned file_channels, float** tmpdata, unsigned length, bool blankData, unsigned format, unsigned sampleRate)
+{
+ if (copiedPart!="") {
+ QFile::remove(copiedPart);
+ }
+ if (!MusEGlobal::getUniqueTmpfileName("tmp_musewav",".wav", copiedPart)) {
+ return;
+ }
+
+ MusECore::SndFile tmpFile(copiedPart);
+ tmpFile.setFormat(format, file_channels, sampleRate);
+ tmpFile.openWrite();
+ tmpFile.write(file_channels, tmpdata, length);
+ tmpFile.close();
+
+ if (blankData) {
+ // Set everything to 0!
+ for (unsigned i=0; i<file_channels; i++) {
+ for (unsigned j=0; j<length; j++) {
+ tmpdata[i][j] = 0;
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------
+// muteSelection
+//---------------------------------------------------------
+void WaveCanvas::muteSelection(unsigned channels, float** data, unsigned length)
+ {
+ // Set everything to 0!
+ for (unsigned i=0; i<channels; i++) {
+ for (unsigned j=0; j<length; j++) {
+ data[i][j] = 0;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// normalizeSelection
+//---------------------------------------------------------
+void WaveCanvas::normalizeSelection(unsigned channels, float** data, unsigned length)
+ {
+ 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);
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// fadeInSelection
+//---------------------------------------------------------
+void WaveCanvas::fadeInSelection(unsigned channels, float** data, unsigned length)
+ {
+ 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);
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// fadeOutSelection
+//---------------------------------------------------------
+void WaveCanvas::fadeOutSelection(unsigned channels, float** data, unsigned length)
+ {
+ 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);
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// reverseSelection
+//---------------------------------------------------------
+void WaveCanvas::reverseSelection(unsigned channels, float** data, unsigned length)
+ {
+ if(length <= 1)
+ return;
+ 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 - 1];
+ data[i][j] = tmpr;
+ data[i][length - j - 1] = tmpl;
+ }
+ }
+ }
+//---------------------------------------------------------
+// applyGain
+//---------------------------------------------------------
+void WaveCanvas::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 WaveCanvas::editExternal(unsigned file_format, unsigned file_samplerate, unsigned file_channels, float** tmpdata, unsigned tmpdatalen)
+ {
+ // Create yet another tmp-file
+ QString exttmpFileName;
+ if (!MusEGlobal::getUniqueTmpfileName("tmp_musewav",".wav", exttmpFileName)) {
+ printf("Could not create temp file - aborting...\n");
+ return;
+ }
+
+ MusECore::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 = fork();
+ if (pid == 0) {
+ if (execlp(MusEGlobal::config.externalWavEditor.toLatin1().constData(), MusEGlobal::config.externalWavEditor.toLatin1().constData(), exttmpFileName.toLatin1().constData(), NULL) == -1) {
+ perror("Failed to launch external editor");
+ // Get out of here
+
+
+ // cannot report error through gui, we are in another fork!
+ //@!TODO: Handle unsuccessful attempts
+ exit(99);
+ }
+ exit(0);
+ }
+ else if (pid == -1) {
+ perror("fork failed");
+ }
+ else {
+ int status;
+ waitpid(pid, &status, 0);
+ //printf ("status=%d\n",status);
+ if( WEXITSTATUS(status) != 0 ){
+ QMessageBox::warning(this, tr("MusE - external editor failed"),
+ tr("MusE was unable to launch the external editor\ncheck if the editor setting in:\n"
+ "Global Settings->Audio:External Waveditor\nis set to a valid editor."));
+ }
+
+ if (exttmpFile.openRead()) {
+ printf("Could not reopen temporary file!\n");
+ }
+ else {
+ // Re-read file again
+ exttmpFile.seek(0, 0);
+ size_t sz = exttmpFile.readWithHeap(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.dirPath();
+ dir.remove(exttmpFileName);
+ dir.remove(exttmpFile.basename() + ".wca");
+ }
+ }
+
+
+
+//---------------------------------------------------------
+// startDrag
+//---------------------------------------------------------
+
+void WaveCanvas::startDrag(MusEGui::CItem* /* item*/, bool copymode)
+ {
+ QMimeData* md = MusECore::selected_events_to_mime(MusECore::partlist_to_set(editor->parts()), 1);
+
+ if (md) {
+ // "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object.
+ // The QDrag must be constructed on the heap with a parent QWidget to ensure that Qt can
+ // clean up after the drag and drop operation has been completed. "
+ QDrag* drag = new QDrag(this);
+ drag->setMimeData(md);
+
+ if (copymode)
+ drag->exec(Qt::CopyAction);
+ else
+ drag->exec(Qt::MoveAction);
+ }
+ }
+
+//---------------------------------------------------------
+// dragEnterEvent
+//---------------------------------------------------------
+
+void WaveCanvas::dragEnterEvent(QDragEnterEvent* event)
+ {
+ //event->accept(Q3TextDrag::canDecode(event));
+ event->acceptProposedAction(); // TODO CHECK Tim.
+ }
+
+//---------------------------------------------------------
+// dragMoveEvent
+//---------------------------------------------------------
+
+void WaveCanvas::dragMoveEvent(QDragMoveEvent*)
+ {
+ //printf("drag move %x\n", this); DELETETHIS (whole function?)
+ //event->acceptProposedAction();
+ }
+
+//---------------------------------------------------------
+// dragLeaveEvent
+//---------------------------------------------------------
+
+void WaveCanvas::dragLeaveEvent(QDragLeaveEvent*)
+ {
+ //printf("drag leave\n"); DELETETHIS (whole function?)
+ //event->acceptProposedAction();
+ }
+
+//---------------------------------------------------------
+// itemPressed
+//---------------------------------------------------------
+
+void WaveCanvas::itemPressed(const MusEGui::CItem*)
+ {
+ }
+
+//---------------------------------------------------------
+// itemReleased
+//---------------------------------------------------------
+
+void WaveCanvas::itemReleased(const MusEGui::CItem*, const QPoint&)
+ {
+ }
+
+//---------------------------------------------------------
+// itemMoved
+//---------------------------------------------------------
+
+void WaveCanvas::itemMoved(const MusEGui::CItem*, const QPoint&)
+ {
+ }
+
+//---------------------------------------------------------
+// curPartChanged
+//---------------------------------------------------------
+
+void WaveCanvas::curPartChanged()
+ {
+ EventCanvas::curPartChanged();
+ editor->setWindowTitle(getCaption());
+ }
+
+//---------------------------------------------------------
+// modifySelected
+//---------------------------------------------------------
+
+void WaveCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int val, bool delta_mode)
+ {
+ // TODO: New WaveCanvas: Convert this routine to frames and remove unneeded operations.
+ QList< QPair<MusECore::EventList*,MusECore::Event> > already_done;
+ MusEGlobal::audio->msgIdle(true);
+ MusEGlobal::song->startUndo();
+ for (MusEGui::iCItem i = items.begin(); i != items.end(); ++i) {
+ if (!(i->second->isSelected()))
+ continue;
+ WEvent* e = (WEvent*)(i->second);
+ MusECore::Event event = e->event();
+ if (event.type() != MusECore::Note)
+ continue;
+
+ MusECore::WavePart* part = (MusECore::WavePart*)(e->part());
+
+ if (already_done.contains(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event)))
+ continue;
+
+ MusECore::Event newEvent = event.clone();
+
+ switch (type) {
+ case MusEGui::NoteInfo::VAL_TIME:
+ {
+ int newTime = val;
+ if(delta_mode)
+ newTime += event.tick();
+ else
+ newTime -= part->tick();
+ if (newTime < 0)
+ newTime = 0;
+ newEvent.setTick(newTime);
+ }
+ break;
+ case MusEGui::NoteInfo::VAL_LEN:
+ {
+ int len = val;
+ if(delta_mode)
+ len += event.lenTick();
+ if (len < 1)
+ len = 1;
+ newEvent.setLenTick(len);
+ }
+ break;
+ case MusEGui::NoteInfo::VAL_VELON:
+ {
+ int velo = val;
+ if(delta_mode)
+ velo += event.velo();
+ if (velo > 127)
+ velo = 127;
+ else if (velo < 0)
+ velo = 0;
+ newEvent.setVelo(velo);
+ }
+ break;
+ case MusEGui::NoteInfo::VAL_VELOFF:
+ {
+ int velo = val;
+ if(delta_mode)
+ velo += event.veloOff();
+ if (velo > 127)
+ velo = 127;
+ else if (velo < 0)
+ velo = 0;
+ newEvent.setVeloOff(velo);
+ }
+ break;
+ case MusEGui::NoteInfo::VAL_PITCH:
+ {
+ int pitch = val;
+ if(delta_mode)
+ pitch += event.pitch();
+ if (pitch > 127)
+ pitch = 127;
+ else if (pitch < 0)
+ pitch = 0;
+ newEvent.setPitch(pitch);
+ }
+ break;
+ }
+
+ MusEGlobal::song->changeEvent(event, newEvent, part);
+ // Indicate do not do port controller values and clone parts.
+ MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false));
+
+ already_done.append(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event));
+ }
+ MusEGlobal::song->endUndo(SC_EVENT_MODIFIED);
+ MusEGlobal::audio->msgIdle(false);
+ }
+
+//---------------------------------------------------------
+// resizeEvent
+//---------------------------------------------------------
+
+void WaveCanvas::resizeEvent(QResizeEvent* ev)
+ {
+ // Readjust all wave canvas item heights
+ bool do_redraw = false;
+ for (iCItem k = items.begin(); k != items.end(); ++k)
+ {
+ if(k->second->height() != ev->size().height())
+ {
+ k->second->setHeight(ev->size().height());
+ do_redraw = true;
+ }
+ }
+
+ if (ev->size().width() != ev->oldSize().width())
+ emit newWidth(ev->size().width());
+ EventCanvas::resizeEvent(ev);
+
+ if(do_redraw)
+ redraw();
+ }
+
+} // namespace MusEGui
diff --git a/muse2/muse/waveedit/wavecanvas.h b/muse2/muse/waveedit/wavecanvas.h
new file mode 100644
index 00000000..df285abc
--- /dev/null
+++ b/muse2/muse/waveedit/wavecanvas.h
@@ -0,0 +1,185 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// wavecanvas.h
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
+//
+// Based on WaveView.cpp and PianoCanvas.cpp
+// (C) Copyright 2000 Werner Schweer (ws@seh.de)
+// and others.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; version 2 of
+// the License, or (at your option) any later version.
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=========================================================
+
+#ifndef __WAVECANVAS_H__
+#define __WAVECANVAS_H__
+
+#include "type_defs.h"
+#include "ecanvas.h"
+#include <QDragEnterEvent>
+#include <QDropEvent>
+#include <QMouseEvent>
+#include <QDragMoveEvent>
+#include <QDragLeaveEvent>
+#include <QWheelEvent>
+#include <QResizeEvent>
+#include <QTimer>
+
+class QRect;
+
+namespace MusECore {
+class SndFileR;
+class WavePart;
+class WaveTrack;
+
+struct WaveEventSelection {
+ SndFileR file;
+ unsigned startframe;
+ unsigned endframe;
+ };
+
+typedef std::list<WaveEventSelection> WaveSelectionList;
+typedef std::list<WaveEventSelection>::iterator iWaveSelection;
+}
+
+namespace MusEGui {
+
+//---------------------------------------------------------
+// WEvent
+// ''visual'' Wave Event
+//---------------------------------------------------------
+
+class WEvent : public CItem {
+ public:
+ WEvent(MusECore::Event& e, MusECore::Part* p, int height);
+ };
+
+//---------------------------------------------------------
+// WaveCanvas
+//---------------------------------------------------------
+
+class WaveCanvas : public EventCanvas {
+ Q_OBJECT
+
+ enum { NORMAL, DRAG } mode;
+ enum { MUTE = 0, NORMALIZE, FADE_IN, FADE_OUT, REVERSE, GAIN, EDIT_EXTERNAL, CUT, COPY, PASTE }; //!< Modify operations
+
+ int yScale;
+ int button;
+ unsigned startSample;
+ unsigned endSample;
+ int colorMode;
+ int selectionStart, selectionStop, dragstartx;
+ int lastGainvalue; //!< Stores the last used gainvalue when specifiying gain value in the editgain dialog
+ QString copiedPart;
+
+ //bool getUniqueTmpfileName(QString& newFilename); //!< Generates unique filename for temporary SndFile
+ MusECore::WaveSelectionList getSelection(unsigned startpos, unsigned stoppos);
+ void modifySelection(int operation, unsigned startpos, unsigned stoppos, double paramA); //!< Modifies selection
+ void muteSelection(unsigned channels, float** data, unsigned length); //!< Mutes selection
+ void normalizeSelection(unsigned channels, float** data, unsigned length); //!< Normalizes selection
+ void fadeInSelection(unsigned channels, float** data, unsigned length); //!< Linear fade in of selection
+ void fadeOutSelection(unsigned channels, float** data, unsigned length); //!< Linear fade out of selection
+ void reverseSelection(unsigned channels, float** data, unsigned length); //!< Reverse selection
+ void applyGain(unsigned channels, float** data, unsigned length, double gain); //!< Apply gain to selection
+ void copySelection(unsigned file_channels, float** tmpdata, unsigned tmpdatalen, bool blankData, unsigned format, unsigned sampleRate);
+ void editExternal(unsigned file_format, unsigned file_samplerate, unsigned channels, float** data, unsigned length);
+ //void applyLadspa(unsigned channels, float** data, unsigned length); //!< Apply LADSPA plugin on selection
+
+
+ protected:
+ virtual QPoint raster(const QPoint&) const;
+ void drawTickRaster(QPainter& p, int x, int y, int w, int h, int raster);
+ void drawParts(QPainter&, const QRect&, bool do_cur_part);
+
+ // REMOVE Tim.
+ //virtual void pdraw(QPainter&, const QRect&);
+ virtual void draw(QPainter&, const QRect&);
+ virtual void viewMouseDoubleClickEvent(QMouseEvent*);
+ virtual void wheelEvent(QWheelEvent*);
+ virtual bool mousePress(QMouseEvent*);
+ virtual void mouseMove(QMouseEvent* event);
+ virtual void mouseRelease(const QPoint&);
+ virtual void drawItem(QPainter&, const CItem*, const QRect&);
+ void drawTopItem(QPainter &p, const QRect &rect);
+ virtual void drawMoving(QPainter&, const CItem*, const QRect&);
+ virtual MusECore::Undo moveCanvasItems(CItemList&, int, int, DragType);
+ virtual bool moveItem(MusECore::Undo&, CItem*, const QPoint&, DragType);
+ virtual CItem* newItem(const QPoint&, int);
+ virtual void resizeItem(CItem*, bool noSnap, bool);
+ virtual void newItem(CItem*, bool noSnap);
+ virtual bool deleteItem(CItem*);
+ virtual void startDrag(CItem* item, bool copymode);
+ virtual void dragEnterEvent(QDragEnterEvent* event);
+ virtual void dragMoveEvent(QDragMoveEvent*);
+ virtual void dragLeaveEvent(QDragLeaveEvent*);
+ virtual CItem* addItem(MusECore::Part*, MusECore::Event&);
+
+ int y2pitch(int) const;
+ int pitch2y(int) const;
+ virtual void drawCanvas(QPainter&, const QRect&);
+ virtual void itemPressed(const CItem*);
+ virtual void itemReleased(const CItem*, const QPoint&);
+ virtual void itemMoved(const CItem*, const QPoint&);
+ virtual void curPartChanged();
+ virtual void resizeEvent(QResizeEvent*);
+
+ private slots:
+ void setPos(int idx, unsigned val, bool adjustScrollbar);
+
+ signals:
+ void quantChanged(int);
+ void rasterChanged(int);
+ void newWidth(int);
+ void mouseWheelMoved(int);
+
+ public slots:
+ void setYScale(int);
+ void waveCmd(int);
+
+ public:
+
+ enum { CMD_MUTE=0, CMD_NORMALIZE, CMD_FADE_IN, CMD_FADE_OUT, CMD_REVERSE,
+ CMD_GAIN_FREE, CMD_GAIN_200, CMD_GAIN_150, CMD_GAIN_75, CMD_GAIN_50, CMD_GAIN_25,
+ CMD_EDIT_COPY, CMD_EDIT_CUT, CMD_EDIT_PASTE, CMD_PASTE_DIALOG, CMD_DEL,
+ CMD_EDIT_EXTERNAL,
+ CMD_QUANTIZE,
+ CMD_SELECT_ALL, CMD_SELECT_NONE, CMD_SELECT_INVERT,
+ CMD_SELECT_ILOOP, CMD_SELECT_OLOOP, CMD_SELECT_PREV_PART, CMD_SELECT_NEXT_PART,
+ CMD_ERASE_MEASURE, CMD_DELETE_MEASURE, CMD_CREATE_MEASURE
+ };
+
+ WaveCanvas(MidiEditor*, QWidget*, int, int);
+ virtual ~WaveCanvas();
+ MusECore::WaveTrack* track() const;
+ void cmd(int cmd);
+ void setColorMode(int mode) {
+ colorMode = mode;
+ redraw();
+ }
+ QString getCaption() const;
+ void songChanged(MusECore::SongChangedFlags_t);
+ void range(int* s, int* e) const { *s = startSample; *e = endSample; }
+ void selectAtTick(unsigned int tick);
+ void selectAtFrame(unsigned int frame);
+ void modifySelected(NoteInfo::ValType type, int val, bool delta_mode = true);
+ void keyPress(QKeyEvent*);
+ };
+
+} // namespace MusEGui
+
+#endif
+
diff --git a/muse2/muse/waveedit/waveedit.cpp b/muse2/muse/waveedit/waveedit.cpp
index e1f18722..8290128f 100644
--- a/muse2/muse/waveedit/waveedit.cpp
+++ b/muse2/muse/waveedit/waveedit.cpp
@@ -3,6 +3,7 @@
// Linux Music Editor
// $Id: waveedit.cpp,v 1.5.2.12 2009/04/06 01:24:54 terminator356 Exp $
// (C) Copyright 2000 Werner Schweer (ws@seh.de)
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -20,6 +21,8 @@
//
//=========================================================
+#include <limits.h>
+
#include <QMenu>
#include <QSignalMapper>
#include <QToolBar>
@@ -41,7 +44,8 @@
#include "waveedit.h"
#include "mtscale.h"
#include "scrollscale.h"
-#include "waveview.h"
+//#include "waveview.h"
+#include "wavecanvas.h"
#include "ttoolbar.h"
#include "globals.h"
#include "audio.h"
@@ -51,6 +55,7 @@
#include "gconfig.h"
#include "icons.h"
#include "shortcuts.h"
+#include "cmd.h"
namespace MusECore {
extern QColor readColor(MusECore::Xml& xml);
@@ -58,6 +63,12 @@ extern QColor readColor(MusECore::Xml& xml);
namespace MusEGui {
+static int waveEditTools = MusEGui::PointerTool | MusEGui::PencilTool | MusEGui::RubberTool |
+ MusEGui::CutTool | MusEGui::CursorTool;
+
+int WaveEdit::_rasterInit = 96;
+int WaveEdit::colorModeInit = 0;
+
//---------------------------------------------------------
// closeEvent
//---------------------------------------------------------
@@ -81,8 +92,10 @@ WaveEdit::WaveEdit(MusECore::PartList* pl)
: MidiEditor(TopWin::WAVE, 1, pl)
{
setFocusPolicy(Qt::NoFocus);
+ colorMode = colorModeInit;
QSignalMapper* mapper = new QSignalMapper(this);
+ QSignalMapper* colorMapper = new QSignalMapper(this);
QAction* act;
//---------Pulldown Menu----------------------------
@@ -95,27 +108,27 @@ WaveEdit::WaveEdit(MusECore::PartList* pl)
menuGain = menuFunctions->addMenu(tr("&Gain"));
act = menuGain->addAction("200%");
- mapper->setMapping(act, CMD_GAIN_200);
+ mapper->setMapping(act, WaveCanvas::CMD_GAIN_200);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuGain->addAction("150%");
- mapper->setMapping(act, CMD_GAIN_150);
+ mapper->setMapping(act, WaveCanvas::CMD_GAIN_150);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuGain->addAction("75%");
- mapper->setMapping(act, CMD_GAIN_75);
+ mapper->setMapping(act, WaveCanvas::CMD_GAIN_75);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuGain->addAction("50%");
- mapper->setMapping(act, CMD_GAIN_50);
+ mapper->setMapping(act, WaveCanvas::CMD_GAIN_50);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuGain->addAction("25%");
- mapper->setMapping(act, CMD_GAIN_25);
+ mapper->setMapping(act, WaveCanvas::CMD_GAIN_25);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuGain->addAction(tr("Other"));
- mapper->setMapping(act, CMD_GAIN_FREE);
+ mapper->setMapping(act, WaveCanvas::CMD_GAIN_FREE);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
connect(mapper, SIGNAL(mapped(int)), this, SLOT(cmd(int)));
@@ -123,65 +136,99 @@ WaveEdit::WaveEdit(MusECore::PartList* pl)
menuFunctions->addSeparator();
copyAction = menuEdit->addAction(tr("&Copy"));
- mapper->setMapping(copyAction, CMD_EDIT_COPY);
+ mapper->setMapping(copyAction, WaveCanvas::CMD_EDIT_COPY);
connect(copyAction, SIGNAL(triggered()), mapper, SLOT(map()));
cutAction = menuEdit->addAction(tr("C&ut"));
- mapper->setMapping(cutAction, CMD_EDIT_CUT);
+ mapper->setMapping(cutAction, WaveCanvas::CMD_EDIT_CUT);
connect(cutAction, SIGNAL(triggered()), mapper, SLOT(map()));
pasteAction = menuEdit->addAction(tr("&Paste"));
- mapper->setMapping(pasteAction, CMD_EDIT_PASTE);
+ mapper->setMapping(pasteAction, WaveCanvas::CMD_EDIT_PASTE);
connect(pasteAction, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuEdit->addAction(tr("Edit in E&xternal Editor"));
- mapper->setMapping(act, CMD_EDIT_EXTERNAL);
+ mapper->setMapping(act, WaveCanvas::CMD_EDIT_EXTERNAL);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuFunctions->addAction(tr("Mute Selection"));
- mapper->setMapping(act, CMD_MUTE);
+ mapper->setMapping(act, WaveCanvas::CMD_MUTE);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuFunctions->addAction(tr("Normalize Selection"));
- mapper->setMapping(act, CMD_NORMALIZE);
+ mapper->setMapping(act, WaveCanvas::CMD_NORMALIZE);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuFunctions->addAction(tr("Fade In Selection"));
- mapper->setMapping(act, CMD_FADE_IN);
+ mapper->setMapping(act, WaveCanvas::CMD_FADE_IN);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuFunctions->addAction(tr("Fade Out Selection"));
- mapper->setMapping(act, CMD_FADE_OUT);
+ mapper->setMapping(act, WaveCanvas::CMD_FADE_OUT);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
act = menuFunctions->addAction(tr("Reverse Selection"));
- mapper->setMapping(act, CMD_REVERSE);
+ mapper->setMapping(act, WaveCanvas::CMD_REVERSE);
connect(act, SIGNAL(triggered()), mapper, SLOT(map()));
select = menuEdit->addMenu(QIcon(*selectIcon), tr("Select"));
selectAllAction = select->addAction(QIcon(*select_allIcon), tr("Select &All"));
- mapper->setMapping(selectAllAction, CMD_SELECT_ALL);
+ mapper->setMapping(selectAllAction, WaveCanvas::CMD_SELECT_ALL);
connect(selectAllAction, SIGNAL(triggered()), mapper, SLOT(map()));
selectNoneAction = select->addAction(QIcon(*select_allIcon), tr("&Deselect All"));
- mapper->setMapping(selectNoneAction, CMD_SELECT_NONE);
+ mapper->setMapping(selectNoneAction, WaveCanvas::CMD_SELECT_NONE);
connect(selectNoneAction, SIGNAL(triggered()), mapper, SLOT(map()));
+ select->addSeparator();
+
+ selectPrevPartAction = select->addAction(QIcon(*select_all_parts_on_trackIcon), tr("&Previous Part"));
+ mapper->setMapping(selectPrevPartAction, WaveCanvas::CMD_SELECT_PREV_PART);
+ connect(selectPrevPartAction, SIGNAL(triggered()), mapper, SLOT(map()));
+
+ selectNextPartAction = select->addAction(QIcon(*select_all_parts_on_trackIcon), tr("&Next Part"));
+ mapper->setMapping(selectNextPartAction, WaveCanvas::CMD_SELECT_NEXT_PART);
+ connect(selectNextPartAction, SIGNAL(triggered()), mapper, SLOT(map()));
+
QMenu* settingsMenu = menuBar()->addMenu(tr("Window &Config"));
+
+ eventColor = settingsMenu->addMenu(tr("&Event Color"));
+
+ QActionGroup* actgrp = new QActionGroup(this);
+ actgrp->setExclusive(true);
+
+ evColorNormalAction = actgrp->addAction(tr("&Part colors"));
+ evColorNormalAction->setCheckable(true);
+ colorMapper->setMapping(evColorNormalAction, 0);
+
+ evColorPartsAction = actgrp->addAction(tr("&Gray"));
+ evColorPartsAction->setCheckable(true);
+ colorMapper->setMapping(evColorPartsAction, 1);
+
+ connect(evColorNormalAction, SIGNAL(triggered()), colorMapper, SLOT(map()));
+ connect(evColorPartsAction, SIGNAL(triggered()), colorMapper, SLOT(map()));
+
+ eventColor->addActions(actgrp->actions());
+
+ connect(colorMapper, SIGNAL(mapped(int)), this, SLOT(eventColorModeChanged(int)));
+
+ settingsMenu->addSeparator();
settingsMenu->addAction(subwinAction);
settingsMenu->addAction(shareAction);
settingsMenu->addAction(fullscreenAction);
-
connect(MusEGlobal::muse, SIGNAL(configChanged()), SLOT(configChanged()));
//--------------------------------------------------
// ToolBar: Solo Cursor1 Cursor2
+ tools2 = new MusEGui::EditToolBar(this, waveEditTools);
+ addToolBar(tools2);
+
addToolBarBreak();
tb1 = addToolBar(tr("WaveEdit tools"));
tb1->setObjectName("WaveEdit tools");
@@ -222,8 +269,9 @@ WaveEdit::WaveEdit(MusECore::PartList* pl)
}
hscroll = new ScrollScale(-32768, 1, xscale, 10000, Qt::Horizontal, mainw, 0, false, 10000.0);
- view = new WaveView(this, mainw, xscale, yscale);
- wview = view; // HACK!
+ //view = new WaveView(this, mainw, xscale, yscale);
+ canvas = new WaveCanvas(this, mainw, xscale, yscale);
+ //wview = canvas; // HACK!
QSizeGrip* corner = new QSizeGrip(mainw);
ymag = new QSlider(Qt::Vertical, mainw);
@@ -235,10 +283,10 @@ WaveEdit::WaveEdit(MusECore::PartList* pl)
time = new MTScale(&_raster, mainw, xscale, true);
ymag->setFixedWidth(16);
- connect(view, SIGNAL(mouseWheelMoved(int)), this, SLOT(moveVerticalSlider(int)));
- connect(ymag, SIGNAL(valueChanged(int)), view, SLOT(setYScale(int)));
- connect(view, SIGNAL(horizontalZoomIn()), SLOT(horizontalZoomIn()));
- connect(view, SIGNAL(horizontalZoomOut()), SLOT(horizontalZoomOut()));
+ connect(canvas, SIGNAL(mouseWheelMoved(int)), this, SLOT(moveVerticalSlider(int)));
+ connect(ymag, SIGNAL(valueChanged(int)), canvas, SLOT(setYScale(int)));
+ connect(canvas, SIGNAL(horizontalZoomIn()), SLOT(horizontalZoomIn()));
+ connect(canvas, SIGNAL(horizontalZoomOut()), SLOT(horizontalZoomOut()));
time->setOrigin(0, 0);
@@ -247,28 +295,38 @@ WaveEdit::WaveEdit(MusECore::PartList* pl)
mainGrid->addWidget(time, 0, 0, 1, 2);
mainGrid->addWidget(MusECore::hLine(mainw), 1, 0, 1, 2);
- mainGrid->addWidget(view, 2, 0);
+ mainGrid->addWidget(canvas, 2, 0);
mainGrid->addWidget(ymag, 2, 1);
mainGrid->addWidget(hscroll, 3, 0);
mainGrid->addWidget(corner, 3, 1, Qt::AlignBottom | Qt::AlignRight);
- view->setFocus();
+ canvas->setFocus();
- connect(hscroll, SIGNAL(scrollChanged(int)), view, SLOT(setXPos(int)));
- connect(hscroll, SIGNAL(scaleChanged(int)), view, SLOT(setXMag(int)));
- setWindowTitle(view->getCaption());
- connect(view, SIGNAL(followEvent(int)), hscroll, SLOT(setOffset(int)));
+ connect(canvas, SIGNAL(toolChanged(int)), tools2, SLOT(set(int)));
+ connect(tools2, SIGNAL(toolChanged(int)), canvas, SLOT(setTool(int)));
+
+ connect(hscroll, SIGNAL(scrollChanged(int)), canvas, SLOT(setXPos(int)));
+ connect(hscroll, SIGNAL(scaleChanged(int)), canvas, SLOT(setXMag(int)));
+ setWindowTitle(canvas->getCaption());
+ connect(canvas, SIGNAL(followEvent(int)), hscroll, SLOT(setOffset(int)));
connect(hscroll, SIGNAL(scrollChanged(int)), time, SLOT(setXPos(int)));
connect(hscroll, SIGNAL(scaleChanged(int)), time, SLOT(setXMag(int)));
-// connect(time, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
- connect(view, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
+ connect(time, SIGNAL(timeChanged(unsigned)), SLOT(timeChanged(unsigned)));
+ connect(canvas, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned)));
- connect(view, SIGNAL(horizontalScroll(unsigned)),hscroll, SLOT(setPos(unsigned)));
+ connect(canvas, SIGNAL(horizontalScroll(unsigned)),hscroll, SLOT(setPos(unsigned)));
+ connect(canvas, SIGNAL(horizontalScrollNoLimit(unsigned)),hscroll, SLOT(setPosNoLimit(unsigned)));
connect(hscroll, SIGNAL(scaleChanged(int)), SLOT(updateHScrollRange()));
connect(MusEGlobal::song, SIGNAL(songChanged(MusECore::SongChangedFlags_t)), SLOT(songChanged1(MusECore::SongChangedFlags_t)));
+ // For the wave editor, let's start with the operation range selection tool.
+ canvas->setTool(MusEGui::CursorTool);
+ tools2->set(MusEGui::CursorTool);
+
+ setEventColorMode(colorMode);
+
initShortcuts();
updateHScrollRange();
@@ -291,6 +349,17 @@ void WaveEdit::initShortcuts()
pasteAction->setShortcut(shortcuts[SHRT_PASTE].key);
selectAllAction->setShortcut(shortcuts[SHRT_SELECT_ALL].key);
selectNoneAction->setShortcut(shortcuts[SHRT_SELECT_NONE].key);
+
+ //selectInvertAction->setShortcut(shortcuts[SHRT_SELECT_INVERT].key);
+ //selectInsideLoopAction->setShortcut(shortcuts[SHRT_SELECT_ILOOP].key);
+ //selectOutsideLoopAction->setShortcut(shortcuts[SHRT_SELECT_OLOOP].key);
+ selectPrevPartAction->setShortcut(shortcuts[SHRT_SELECT_PREV_PART].key);
+ selectNextPartAction->setShortcut(shortcuts[SHRT_SELECT_NEXT_PART].key);
+
+ eventColor->menuAction()->setShortcut(shortcuts[SHRT_EVENT_COLOR].key);
+ //evColorNormalAction->setShortcut(shortcuts[ ].key);
+ //evColorPartsAction->setShortcut(shortcuts[ ].key);
+
}
//---------------------------------------------------------
@@ -299,9 +368,15 @@ void WaveEdit::initShortcuts()
void WaveEdit::configChanged()
{
- view->setBg(MusEGlobal::config.waveEditBackgroundColor);
- selectAllAction->setShortcut(shortcuts[SHRT_SELECT_ALL].key);
- selectNoneAction->setShortcut(shortcuts[SHRT_SELECT_NONE].key);
+ if (MusEGlobal::config.canvasBgPixmap.isEmpty()) {
+ canvas->setBg(MusEGlobal::config.waveEditBackgroundColor);
+ canvas->setBg(QPixmap());
+ }
+ else {
+ canvas->setBg(QPixmap(MusEGlobal::config.canvasBgPixmap));
+ }
+
+ initShortcuts();
}
//---------------------------------------------------------
@@ -310,17 +385,39 @@ void WaveEdit::configChanged()
void WaveEdit::updateHScrollRange()
{
int s, e;
- wview->range(&s, &e);
- // Show one more measure.
- e += AL::sigmap.ticksMeasure(e);
- // Show another quarter measure due to imprecise drawing at canvas end point.
- e += AL::sigmap.ticksMeasure(e) / 4;
+ canvas->range(&s, &e); // Range in frames
+ unsigned tm = AL::sigmap.ticksMeasure(MusEGlobal::tempomap.frame2tick(e));
+
+ // Show one more measure, and show another quarter measure due to imprecise drawing at canvas end point.
+ //e += MusEGlobal::tempomap.tick2frame(tm + tm / 4); // TODO: Try changing scrollbar to use units of frames?
+ e += (tm + tm / 4);
+
// Compensate for the vscroll width.
//e += wview->rmapxDev(-vscroll->width());
int s1, e1;
- hscroll->range(&s1, &e1);
+ hscroll->range(&s1, &e1); // ...
if(s != s1 || e != e1)
- hscroll->setRange(s, e);
+ hscroll->setRange(s, e); // ...
+}
+
+//---------------------------------------------------------
+// timeChanged
+//---------------------------------------------------------
+
+void WaveEdit::timeChanged(unsigned t)
+{
+ if(t == INT_MAX)
+ {
+ // Let the PosLabels disable themselves with INT_MAX.
+ pos1->setValue(t);
+ pos2->setValue(t);
+ return;
+ }
+
+ unsigned frame = MusEGlobal::tempomap.tick2frame(t);
+ pos1->setValue(t);
+ pos2->setValue(frame);
+ time->setPos(3, t, false);
}
//---------------------------------------------------------
@@ -329,10 +426,16 @@ void WaveEdit::updateHScrollRange()
void WaveEdit::setTime(unsigned samplepos)
{
-// printf("setTime %d %x\n", samplepos, samplepos);
+ if(samplepos == INT_MAX)
+ {
+ // Let the PosLabels disable themselves with INT_MAX.
+ pos1->setValue(samplepos);
+ pos2->setValue(samplepos);
+ return;
+ }
+
unsigned tick = MusEGlobal::tempomap.frame2tick(samplepos);
pos1->setValue(tick);
- //pos2->setValue(tick);
pos2->setValue(samplepos);
time->setPos(3, tick, false);
}
@@ -343,7 +446,6 @@ void WaveEdit::setTime(unsigned samplepos)
WaveEdit::~WaveEdit()
{
- // MusEGlobal::undoRedo->removeFrom(tools); // p4.0.6 Removed
}
//---------------------------------------------------------
@@ -352,7 +454,7 @@ WaveEdit::~WaveEdit()
void WaveEdit::cmd(int n)
{
- view->cmd(n);
+ ((WaveCanvas*)canvas)->cmd(n);
}
//---------------------------------------------------------
@@ -368,6 +470,10 @@ void WaveEdit::readConfiguration(MusECore::Xml& xml)
case MusECore::Xml::TagStart:
if (tag == "bgcolor")
MusEGlobal::config.waveEditBackgroundColor = readColor(xml);
+ else if (tag == "raster")
+ _rasterInit = xml.parseInt();
+ else if (tag == "colormode")
+ colorModeInit = xml.parseInt();
else if (tag == "topwin")
TopWin::readConfiguration(WAVE, xml);
else
@@ -393,6 +499,8 @@ void WaveEdit::writeConfiguration(int level, MusECore::Xml& xml)
{
xml.tag(level++, "waveedit");
xml.colorTag(level, "bgcolor", MusEGlobal::config.waveEditBackgroundColor);
+ xml.intTag(level, "raster", _rasterInit);
+ xml.intTag(level, "colormode", colorModeInit);
TopWin::writeConfiguration(WAVE, level,xml);
xml.tag(level, "/waveedit");
}
@@ -406,6 +514,7 @@ void WaveEdit::writeStatus(int level, MusECore::Xml& xml) const
writePartList(level, xml);
xml.tag(level++, "waveedit");
MidiEditor::writeStatus(level, xml);
+ xml.intTag(level, "tool", int(canvas->tool()));
xml.intTag(level, "xpos", hscroll->pos());
xml.intTag(level, "xmag", hscroll->mag());
xml.intTag(level, "ymag", ymag->value());
@@ -427,6 +536,11 @@ void WaveEdit::readStatus(MusECore::Xml& xml)
case MusECore::Xml::TagStart:
if (tag == "midieditor")
MidiEditor::readStatus(xml);
+ else if (tag == "tool") {
+ int tool = xml.parseInt();
+ canvas->setTool(tool);
+ tools2->set(tool);
+ }
else if (tag == "xmag")
hscroll->setMag(xml.parseInt());
else if (tag == "ymag")
@@ -486,14 +600,170 @@ void WaveEdit::soloChanged(bool flag)
void WaveEdit::keyPressEvent(QKeyEvent* event)
{
+// TODO: Raster:
+// int index;
+// int n = sizeof(rasterTable)/sizeof(*rasterTable);
+// for (index = 0; index < n; ++index)
+// if (rasterTable[index] == raster())
+// break;
+// if (index == n) {
+// index = 0;
+// // raster 1 is not in table
+// }
+// int off = (index / 9) * 9;
+// index = index % 9;
+
+// int val = 0;
+
+ WaveCanvas* wc = (WaveCanvas*)canvas;
int key = event->key();
+
+ if (((QInputEvent*)event)->modifiers() & Qt::ShiftModifier)
+ key += Qt::SHIFT;
+ if (((QInputEvent*)event)->modifiers() & Qt::AltModifier)
+ key += Qt::ALT;
+ if (((QInputEvent*)event)->modifiers() & Qt::ControlModifier)
+ key+= Qt::CTRL;
+
if (key == Qt::Key_Escape) {
close();
return;
}
- else {
+
+ else if (key == shortcuts[SHRT_POS_INC].key) {
+ wc->waveCmd(CMD_RIGHT);
+ return;
+ }
+ else if (key == shortcuts[SHRT_POS_DEC].key) {
+ wc->waveCmd(CMD_LEFT);
+ return;
+ }
+ else if (key == shortcuts[SHRT_POS_INC_NOSNAP].key) {
+ wc->waveCmd(CMD_RIGHT_NOSNAP);
+ return;
+ }
+ else if (key == shortcuts[SHRT_POS_DEC_NOSNAP].key) {
+ wc->waveCmd(CMD_LEFT_NOSNAP);
+ return;
+ }
+ else if (key == shortcuts[SHRT_INSERT_AT_LOCATION].key) {
+ wc->waveCmd(CMD_INSERT);
+ return;
+ }
+ else if (key == Qt::Key_Backspace) {
+ wc->waveCmd(CMD_BACKSPACE);
+ return;
+ }
+
+ else if (key == shortcuts[SHRT_TOOL_POINTER].key) {
+ tools2->set(MusEGui::PointerTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_TOOL_PENCIL].key) {
+ tools2->set(MusEGui::PencilTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_TOOL_RUBBER].key) {
+ tools2->set(MusEGui::RubberTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_TOOL_SCISSORS].key) {
+ tools2->set(MusEGui::CutTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_TOOL_CURSOR].key) {
+ tools2->set(MusEGui::CursorTool);
+ return;
+ }
+ else if (key == shortcuts[SHRT_EVENT_COLOR].key) {
+ if (colorMode == 0)
+ colorMode = 1;
+ else if (colorMode == 1)
+ colorMode = 0;
+ setEventColorMode(colorMode);
+ return;
+ }
+
+ // TODO: New WaveCanvas: Convert some of these to use frames.
+ else if (key == shortcuts[SHRT_ZOOM_IN].key) {
+ int mag = hscroll->mag();
+ int zoomlvl = MusEGui::ScrollScale::getQuickZoomLevel(mag);
+ if (zoomlvl < MusEGui::ScrollScale::zoomLevels-1)
+ zoomlvl++;
+
+ int newmag = MusEGui::ScrollScale::convertQuickZoomLevelToMag(zoomlvl);
+ hscroll->setMag(newmag);
+ //printf("mag = %d zoomlvl = %d newmag = %d\n", mag, zoomlvl, newmag);
+ return;
+ }
+ else if (key == shortcuts[SHRT_ZOOM_OUT].key) {
+ int mag = hscroll->mag();
+ int zoomlvl = MusEGui::ScrollScale::getQuickZoomLevel(mag);
+ if (zoomlvl > 1)
+ zoomlvl--;
+
+ int newmag = MusEGui::ScrollScale::convertQuickZoomLevelToMag(zoomlvl);
+ hscroll->setMag(newmag);
+ //printf("mag = %d zoomlvl = %d newmag = %d\n", mag, zoomlvl, newmag);
+ return;
+ }
+ else if (key == shortcuts[SHRT_GOTO_CPOS].key) {
+ MusECore::PartList* p = this->parts();
+ MusECore::Part* first = p->begin()->second;
+ hscroll->setPos(MusEGlobal::song->cpos() - first->tick() );
+ return;
+ }
+ else if (key == shortcuts[SHRT_SCROLL_LEFT].key) {
+ int pos = hscroll->pos() - MusEGlobal::config.division;
+ if (pos < 0)
+ pos = 0;
+ hscroll->setPos(pos);
+ return;
+ }
+ else if (key == shortcuts[SHRT_SCROLL_RIGHT].key) {
+ int pos = hscroll->pos() + MusEGlobal::config.division;
+ hscroll->setPos(pos);
+ return;
+ }
+
+// TODO: Raster:
+// else if (key == shortcuts[SHRT_SET_QUANT_1].key)
+// val = rasterTable[8 + off];
+// else if (key == shortcuts[SHRT_SET_QUANT_2].key)
+// val = rasterTable[7 + off];
+// else if (key == shortcuts[SHRT_SET_QUANT_3].key)
+// val = rasterTable[6 + off];
+// else if (key == shortcuts[SHRT_SET_QUANT_4].key)
+// val = rasterTable[5 + off];
+// else if (key == shortcuts[SHRT_SET_QUANT_5].key)
+// val = rasterTable[4 + off];
+// else if (key == shortcuts[SHRT_SET_QUANT_6].key)
+// val = rasterTable[3 + off];
+// else if (key == shortcuts[SHRT_SET_QUANT_7].key)
+// val = rasterTable[2 + off];
+// else if (key == shortcuts[SHRT_TOGGLE_TRIOL].key)
+// val = rasterTable[index + ((off == 0) ? 9 : 0)];
+// else if (key == shortcuts[SHRT_TOGGLE_PUNCT].key)
+// val = rasterTable[index + ((off == 18) ? 9 : 18)];
+// else if (key == shortcuts[SHRT_TOGGLE_PUNCT2].key) {//CDW
+// if ((off == 18) && (index > 2)) {
+// val = rasterTable[index + 9 - 1];
+// }
+// else if ((off == 9) && (index < 8)) {
+// val = rasterTable[index + 18 + 1];
+// }
+// else
+// return;
+// }
+
+ else { //Default:
event->ignore();
+ return;
}
+
+ // TODO: Raster:
+ //setRaster(val);
+ //toolbar->setRaster(_raster);
}
//---------------------------------------------------------
@@ -540,9 +810,38 @@ void WaveEdit::focusCanvas()
{
if(MusEGlobal::config.smartFocus)
{
- view->setFocus();
- view->activateWindow();
+ canvas->setFocus();
+ canvas->activateWindow();
}
}
+//---------------------------------------------------------
+// eventColorModeChanged
+//---------------------------------------------------------
+
+void WaveEdit::eventColorModeChanged(int mode)
+ {
+ colorMode = mode;
+ colorModeInit = colorMode;
+
+ ((WaveCanvas*)(canvas))->setColorMode(colorMode);
+ }
+
+//---------------------------------------------------------
+// setEventColorMode
+//---------------------------------------------------------
+
+void WaveEdit::setEventColorMode(int mode)
+ {
+ colorMode = mode;
+ colorModeInit = colorMode;
+
+ evColorNormalAction->setChecked(mode == 0);
+ evColorPartsAction->setChecked(mode == 1);
+
+ ((WaveCanvas*)(canvas))->setColorMode(colorMode);
+ }
+
+
+
} // namespace MusEGui
diff --git a/muse2/muse/waveedit/waveedit.h b/muse2/muse/waveedit/waveedit.h
index d52eb986..2d74391a 100644
--- a/muse2/muse/waveedit/waveedit.h
+++ b/muse2/muse/waveedit/waveedit.h
@@ -3,6 +3,7 @@
// Linux Music Editor
// $Id: waveedit.h,v 1.3.2.8 2008/01/26 07:23:21 terminator356 Exp $
// (C) Copyright 2000 Werner Schweer (ws@seh.de)
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -33,6 +34,7 @@
#include "type_defs.h"
#include "midieditor.h"
+#include "tools.h"
class QAction;
class QResizeEvent;
@@ -48,7 +50,7 @@ namespace MusEGui {
class PosLabel;
class ScrollScale;
class SNode;
-class WaveView;
+class WaveCanvas;
//---------------------------------------------------------
// WaveEdit
@@ -57,7 +59,6 @@ class WaveView;
class WaveEdit : public MidiEditor {
Q_OBJECT
- WaveView* view;
QSlider* ymag;
QToolBar* tb1;
QToolButton* solo;
@@ -68,22 +69,32 @@ class WaveEdit : public MidiEditor {
QAction* cutAction;
QAction* copyAction;
QAction* pasteAction;
-
+ QAction* selectPrevPartAction;
+ QAction* selectNextPartAction;
+ QAction* evColorNormalAction;
+ QAction* evColorPartsAction;
+ MusEGui::EditToolBar* tools2;
+ QMenu* menuFunctions, *select, *menuGain, *eventColor;
+ int colorMode;
+ static int _rasterInit;
+ static int colorModeInit;
+
virtual void closeEvent(QCloseEvent*);
virtual void keyPressEvent(QKeyEvent*);
- QMenu* menuFunctions, *select, *menuGain;
-
void initShortcuts();
+ void setEventColorMode(int);
private slots:
void cmd(int);
+ void timeChanged(unsigned t);
void setTime(unsigned t);
void songChanged1(MusECore::SongChangedFlags_t);
void soloChanged(bool flag);
void moveVerticalSlider(int val);
+ void eventColorModeChanged(int);
public slots:
void configChanged();
@@ -102,12 +113,6 @@ class WaveEdit : public MidiEditor {
virtual void writeStatus(int, MusECore::Xml&) const;
static void readConfiguration(MusECore::Xml&);
static void writeConfiguration(int, MusECore::Xml&);
-
- enum { CMD_MUTE=0, CMD_NORMALIZE, CMD_FADE_IN, CMD_FADE_OUT, CMD_REVERSE,
- CMD_GAIN_FREE, CMD_GAIN_200, CMD_GAIN_150, CMD_GAIN_75, CMD_GAIN_50, CMD_GAIN_25,
- CMD_EDIT_COPY, CMD_EDIT_CUT, CMD_EDIT_PASTE,
- CMD_EDIT_EXTERNAL,
- CMD_SELECT_ALL, CMD_SELECT_NONE };
};
} // namespace MusEGui
diff --git a/muse2/muse/widgets/canvas.cpp b/muse2/muse/widgets/canvas.cpp
index a4617d53..f9280ab5 100644
--- a/muse2/muse/widgets/canvas.cpp
+++ b/muse2/muse/widgets/canvas.cpp
@@ -374,7 +374,7 @@ void Canvas::draw(QPainter& p, const QRect& rect)
// Draw unselected parts.
list2.push_back(ci);
}
- }
+ }
int i;
int sz = list1.size();
for(i = 0; i != sz; ++i)
diff --git a/muse2/muse/widgets/canvas.h b/muse2/muse/widgets/canvas.h
index fe26c25a..74de63c5 100644
--- a/muse2/muse/widgets/canvas.h
+++ b/muse2/muse/widgets/canvas.h
@@ -176,7 +176,7 @@ class Canvas : public View {
public slots:
void setTool(int t);
- void setPos(int, unsigned, bool adjustScrollbar);
+ virtual void setPos(int, unsigned, bool adjustScrollbar);
void scrollTimerDone(void);
void redirectedWheelEvent(QWheelEvent*);
diff --git a/muse2/muse/widgets/poslabel.cpp b/muse2/muse/widgets/poslabel.cpp
index b893c58d..5687089c 100644
--- a/muse2/muse/widgets/poslabel.cpp
+++ b/muse2/muse/widgets/poslabel.cpp
@@ -123,6 +123,14 @@ void PosLabel::updateValue()
void PosLabel::setSampleValue(unsigned val)
{
+ if (val == INT_MAX)
+ {
+ setEnabled(false);
+ return;
+ }
+ if(!isEnabled())
+ setEnabled(true);
+
if (val == _sampleValue)
return;
_sampleValue = val;
@@ -135,6 +143,14 @@ void PosLabel::setSampleValue(unsigned val)
void PosLabel::setTickValue(unsigned val)
{
+ if (val == INT_MAX)
+ {
+ setEnabled(false);
+ return;
+ }
+ if(!isEnabled())
+ setEnabled(true);
+
if (val == _tickValue)
return;
if (val >= MAX_TICK)
@@ -153,6 +169,14 @@ void PosLabel::setTickValue(unsigned val)
void PosLabel::setValue(unsigned val)
{
+ if (val == INT_MAX)
+ {
+ setEnabled(false);
+ return;
+ }
+ if(!isEnabled())
+ setEnabled(true);
+
unsigned oval = _smpte ? _sampleValue : _tickValue;
if (val == oval)
return;