summaryrefslogtreecommitdiffstats
path: root/src/gui/application/RosegardenGUIView.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/application/RosegardenGUIView.cpp')
-rw-r--r--src/gui/application/RosegardenGUIView.cpp2041
1 files changed, 2041 insertions, 0 deletions
diff --git a/src/gui/application/RosegardenGUIView.cpp b/src/gui/application/RosegardenGUIView.cpp
new file mode 100644
index 0000000..c61b51e
--- /dev/null
+++ b/src/gui/application/RosegardenGUIView.cpp
@@ -0,0 +1,2041 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
+
+/*
+ Rosegarden
+ A MIDI and audio sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <[email protected]>,
+ Chris Cannam <[email protected]>,
+ Richard Bown <[email protected]>
+
+ The moral rights of Guillaume Laurent, Chris Cannam, and Richard
+ Bown to claim authorship of this work have been asserted.
+
+ Other copyrights also apply to some parts of this work. Please
+ see the AUTHORS file and individual file headers for details.
+
+ 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; either version 2 of the
+ License, or (at your option) any later version. See the file
+ COPYING included with this distribution for more information.
+*/
+
+
+#include "RosegardenGUIView.h"
+#include <kapplication.h>
+
+#include "sound/Midi.h"
+#include "gui/editors/segment/TrackButtons.h"
+#include <klocale.h>
+#include "misc/Debug.h"
+#include "misc/Strings.h"
+#include "document/ConfigGroups.h"
+#include "gui/application/RosegardenDCOP.h"
+#include "base/AudioLevel.h"
+#include "base/Composition.h"
+#include "base/Instrument.h"
+#include "base/MidiDevice.h"
+#include "base/MidiProgram.h"
+#include "base/NotationTypes.h"
+#include "base/RealTime.h"
+#include "base/RulerScale.h"
+#include "base/Segment.h"
+#include "base/Selection.h"
+#include "base/Studio.h"
+#include "base/Track.h"
+#include "commands/segment/AudioSegmentAutoSplitCommand.h"
+#include "commands/segment/AudioSegmentInsertCommand.h"
+#include "commands/segment/SegmentSingleRepeatToCopyCommand.h"
+#include "document/MultiViewCommandHistory.h"
+#include "document/RosegardenGUIDoc.h"
+#include "RosegardenApplication.h"
+#include "gui/configuration/GeneralConfigurationPage.h"
+#include "gui/configuration/AudioConfigurationPage.h"
+#include "gui/dialogs/AudioSplitDialog.h"
+#include "gui/dialogs/AudioManagerDialog.h"
+#include "gui/dialogs/DocumentConfigureDialog.h"
+#include "gui/dialogs/TempoDialog.h"
+#include "gui/editors/eventlist/EventView.h"
+#include "gui/editors/matrix/MatrixView.h"
+#include "gui/editors/notation/NotationView.h"
+#include "gui/editors/parameters/InstrumentParameterBox.h"
+#include "gui/editors/parameters/SegmentParameterBox.h"
+#include "gui/editors/parameters/TrackParameterBox.h"
+#include "gui/editors/segment/segmentcanvas/CompositionView.h"
+#include "gui/editors/segment/segmentcanvas/SegmentSelector.h"
+#include "gui/editors/segment/TrackEditor.h"
+#include "gui/seqmanager/SequenceManager.h"
+#include "gui/seqmanager/SequencerMapper.h"
+#include "gui/rulers/ChordNameRuler.h"
+#include "gui/rulers/LoopRuler.h"
+#include "gui/rulers/TempoRuler.h"
+#include "gui/rulers/StandardRuler.h"
+#include "gui/widgets/ProgressDialog.h"
+#include "gui/widgets/CurrentProgressDialog.h"
+#include "RosegardenGUIApp.h"
+#include "SetWaitCursor.h"
+#include "sound/AudioFile.h"
+#include "sound/AudioFileManager.h"
+#include "sound/MappedEvent.h"
+#include <kcommand.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <qapplication.h>
+#include <qcursor.h>
+#include <qdialog.h>
+#include <qfileinfo.h>
+#include <qobject.h>
+#include <qstring.h>
+#include <qvbox.h>
+#include <qwidget.h>
+
+
+namespace Rosegarden
+{
+
+// Use this to define the basic unit of the main QCanvas size.
+//
+// This apparently arbitrary figure is what we think is an
+// appropriate width in pixels for a 4/4 bar. Beware of making it
+// too narrow, as shorter bars will be proportionally smaller --
+// the visual difference between 2/4 and 4/4 is perhaps greater
+// than it sounds.
+//
+static double barWidth44 = 100.0;
+
+const QWidget *RosegardenGUIView::m_lastActiveMainWindow = 0;
+
+// This is the maximum number of matrix, event view or percussion
+// matrix editors to open in a single operation (not the maximum that
+// can be open at a time -- there isn't one)
+//
+static int maxEditorsToOpen = 8;
+
+RosegardenGUIView::RosegardenGUIView(bool showTrackLabels,
+ SegmentParameterBox* segmentParameterBox,
+ InstrumentParameterBox* instrumentParameterBox,
+ TrackParameterBox* trackParameterBox,
+ QWidget *parent,
+ const char* /*name*/)
+ : QVBox(parent),
+ m_rulerScale(0),
+ m_trackEditor(0),
+ m_segmentParameterBox(segmentParameterBox),
+ m_instrumentParameterBox(instrumentParameterBox),
+ m_trackParameterBox(trackParameterBox)
+{
+ RosegardenGUIDoc* doc = getDocument();
+ Composition *comp = &doc->getComposition();
+
+ double unitsPerPixel =
+ TimeSignature(4, 4).getBarDuration() / barWidth44;
+ m_rulerScale = new SimpleRulerScale(comp, 0, unitsPerPixel);
+
+ // Construct the trackEditor first so we can then
+ // query it for placement information
+ //
+ m_trackEditor = new TrackEditor(doc, this,
+ m_rulerScale, showTrackLabels, unitsPerPixel, this /*hbox*/);
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editSegment(Segment*)),
+ SLOT(slotEditSegment(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editSegmentNotation(Segment*)),
+ SLOT(slotEditSegmentNotation(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editSegmentMatrix(Segment*)),
+ SLOT(slotEditSegmentMatrix(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editSegmentAudio(Segment*)),
+ SLOT(slotEditSegmentAudio(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(audioSegmentAutoSplit(Segment*)),
+ SLOT(slotSegmentAutoSplit(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editSegmentEventList(Segment*)),
+ SLOT(slotEditSegmentEventList(Segment*)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(editRepeat(Segment*, timeT)),
+ SLOT(slotEditRepeat(Segment*, timeT)));
+
+ connect(m_trackEditor->getSegmentCanvas(),
+ SIGNAL(setPointerPosition(timeT)),
+ doc, SLOT(slotSetPointerPosition(timeT)));
+
+ connect(m_trackEditor,
+ SIGNAL(droppedDocument(QString)),
+ parent,
+ SLOT(slotOpenDroppedURL(QString)));
+
+ connect(m_trackEditor,
+ SIGNAL(droppedAudio(QString)),
+ this,
+ SLOT(slotDroppedAudio(QString)));
+
+ connect(m_trackEditor,
+ SIGNAL(droppedNewAudio(QString)),
+ this,
+ SLOT(slotDroppedNewAudio(QString)));
+
+ connect(m_instrumentParameterBox,
+ SIGNAL(changeInstrumentLabel(InstrumentId, QString)),
+ this,
+ SLOT(slotChangeInstrumentLabel(InstrumentId, QString)));
+
+ connect(m_instrumentParameterBox,
+ SIGNAL(changeInstrumentLabel(InstrumentId, QString)),
+ m_trackParameterBox,
+ SLOT(slotInstrumentLabelChanged(InstrumentId, QString)));
+
+ connect(m_trackEditor->getTrackButtons(),
+ SIGNAL(nameChanged()),
+ m_trackParameterBox,
+ SLOT(slotSelectedTrackNameChanged()));
+
+ connect(m_trackEditor->getTrackButtons(),
+ SIGNAL(instrumentSelected(int)),
+ m_trackParameterBox,
+ SLOT(slotUpdateControls(int)));
+
+ connect(m_trackParameterBox,
+ SIGNAL(instrumentSelected(TrackId, int)),
+ m_trackEditor->getTrackButtons(),
+ SLOT(slotTrackInstrumentSelection(TrackId, int)));
+
+ connect(this, SIGNAL(controllerDeviceEventReceived(MappedEvent *, const void *)),
+ this, SLOT(slotControllerDeviceEventReceived(MappedEvent *, const void *)));
+
+ if (doc) {
+ /* signal no longer exists
+ connect(doc, SIGNAL(recordingSegmentUpdated(Segment *,
+ timeT)),
+ this, SLOT(slotUpdateRecordingSegment(Segment *,
+ timeT)));
+ */
+
+ QObject::connect
+ (getCommandHistory(), SIGNAL(commandExecuted()),
+ m_trackEditor->getSegmentCanvas(), SLOT(slotUpdateSegmentsDrawBuffer()));
+ }
+}
+
+RosegardenGUIView::~RosegardenGUIView()
+{
+ RG_DEBUG << "~RosegardenGUIView()" << endl;
+ delete m_rulerScale;
+}
+
+RosegardenGUIDoc*
+RosegardenGUIView::getDocument() const
+{
+ return RosegardenGUIApp::self()->getDocument();
+}
+
+void RosegardenGUIView::print(Composition* p, bool previewOnly)
+{
+ SetWaitCursor waitCursor;
+
+ std::vector<Segment *> segmentsToEdit;
+
+ for (Composition::iterator i = p->begin(); i != p->end(); ++i) {
+ if ((*i)->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(*i);
+ }
+ }
+
+ if (segmentsToEdit.empty()) {
+ KMessageBox::sorry(this, i18n("No non-audio segments in composition"));
+ return ;
+ }
+
+ NotationView *notationView = new NotationView(getDocument(),
+ segmentsToEdit,
+ this,
+ (NotationView *)0);
+
+ if (!notationView->isOK()) {
+ RG_DEBUG << "RosegardenGUIView::print : operation cancelled" << endl;
+ delete notationView;
+ return ;
+ }
+
+ notationView->print(previewOnly);
+
+ delete notationView;
+}
+
+void RosegardenGUIView::selectTool(const QString toolName)
+{
+ m_trackEditor->getSegmentCanvas()->slotSetTool(toolName);
+}
+
+bool
+RosegardenGUIView::haveSelection()
+{
+ return m_trackEditor->getSegmentCanvas()->haveSelection();
+}
+
+SegmentSelection
+RosegardenGUIView::getSelection()
+{
+ return m_trackEditor->getSegmentCanvas()->getSelectedSegments();
+}
+
+void RosegardenGUIView::updateSelectionContents()
+{
+ m_trackEditor->getSegmentCanvas()->updateSelectionContents();
+}
+
+/* hjj: WHAT DO DO WITH THIS ?
+void
+RosegardenGUIView::slotEditMetadata(QString name)
+{
+ const QWidget *ww = dynamic_cast<const QWidget *>(sender());
+ QWidget *w = const_cast<QWidget *>(ww);
+
+ DocumentConfigureDialog *configDlg =
+ new DocumentConfigureDialog(getDocument(), w ? w : this);
+
+ configDlg->selectMetadata(name);
+
+ configDlg->show();
+}
+*/
+
+void RosegardenGUIView::slotEditSegment(Segment* segment)
+{
+ Segment::SegmentType type = Segment::Internal;
+
+ if (segment) {
+ type = segment->getType();
+ } else {
+ if (haveSelection()) {
+
+ bool haveType = false;
+
+ SegmentSelection selection = getSelection();
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+
+ Segment::SegmentType myType = (*i)->getType();
+ if (haveType) {
+ if (myType != type) {
+ KMessageBox::sorry(this, i18n("Selection must contain only audio or non-audio segments"));
+ return ;
+ }
+ } else {
+ type = myType;
+ haveType = true;
+ segment = *i;
+ }
+ }
+ } else
+ return ;
+ }
+
+ if (type == Segment::Audio) {
+ slotEditSegmentAudio(segment);
+ } else {
+
+ KConfig* config = kapp->config();
+ config->setGroup(GeneralOptionsConfigGroup);
+ GeneralConfigurationPage::DoubleClickClient
+ client =
+ (GeneralConfigurationPage::DoubleClickClient)
+ (config->readUnsignedNumEntry("doubleclickclient",
+ (unsigned int)GeneralConfigurationPage::NotationView));
+
+ if (client == GeneralConfigurationPage::MatrixView) {
+
+ bool isPercussion = false;
+ Track *track = getDocument()->getComposition().getTrackById
+ (segment->getTrack());
+ if (track) {
+ InstrumentId iid = track->getInstrument();
+ Instrument *instrument =
+ getDocument()->getStudio().getInstrumentById(iid);
+ if (instrument && instrument->isPercussion()) isPercussion = true;
+ }
+
+ if (isPercussion) {
+ slotEditSegmentPercussionMatrix(segment);
+ } else {
+ slotEditSegmentMatrix(segment);
+ }
+
+ } else if (client == GeneralConfigurationPage::EventView) {
+ slotEditSegmentEventList(segment);
+ } else {
+ slotEditSegmentNotation(segment);
+ }
+ }
+}
+
+void RosegardenGUIView::slotEditRepeat(Segment *segment,
+ timeT time)
+{
+ SegmentSingleRepeatToCopyCommand *command =
+ new SegmentSingleRepeatToCopyCommand(segment, time);
+ slotAddCommandToHistory(command);
+}
+
+void RosegardenGUIView::slotEditSegmentNotation(Segment* p)
+{
+ SetWaitCursor waitCursor;
+ std::vector<Segment *> segmentsToEdit;
+
+ RG_DEBUG << "\n\n\n\nRosegardenGUIView::slotEditSegmentNotation: p is " << p << endl;
+
+ // The logic here is: If we're calling for this operation to
+ // happen on a particular segment, then open that segment and if
+ // it's part of a selection open all other selected segments too.
+ // If we're not calling for any particular segment, then open all
+ // selected segments if there are any.
+
+ if (haveSelection()) {
+
+ SegmentSelection selection = getSelection();
+
+ if (!p || (selection.find(p) != selection.end())) {
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(*i);
+ }
+ }
+ } else {
+ if (p->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(p);
+ }
+ }
+
+ } else if (p) {
+ if (p->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(p);
+ }
+ } else {
+ return ;
+ }
+
+ if (segmentsToEdit.empty()) {
+ KMessageBox::sorry(this, i18n("No non-audio segments selected"));
+ return ;
+ }
+
+ slotEditSegmentsNotation(segmentsToEdit);
+}
+
+void RosegardenGUIView::slotEditSegmentsNotation(std::vector<Segment *> segmentsToEdit)
+{
+ NotationView *view = createNotationView(segmentsToEdit);
+ if (view)
+ view->show();
+}
+
+NotationView *
+RosegardenGUIView::createNotationView(std::vector<Segment *> segmentsToEdit)
+{
+ NotationView *notationView =
+ new NotationView(getDocument(), segmentsToEdit, this, true);
+
+ if (!notationView->isOK()) {
+ RG_DEBUG << "slotEditSegmentNotation : operation cancelled" << endl;
+ delete notationView;
+ return 0;
+ }
+
+ // For tempo changes (ugh -- it'd be nicer to make a tempo change
+ // command that could interpret all this stuff from the dialog)
+ //
+ connect(notationView, SIGNAL(changeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)),
+ RosegardenGUIApp::self(), SLOT(slotChangeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)));
+
+
+ connect(notationView, SIGNAL(windowActivated()),
+ this, SLOT(slotActiveMainWindowChanged()));
+
+ connect(notationView, SIGNAL(selectTrack(int)),
+ this, SLOT(slotSelectTrackSegments(int)));
+
+ connect(notationView, SIGNAL(play()),
+ RosegardenGUIApp::self(), SLOT(slotPlay()));
+ connect(notationView, SIGNAL(stop()),
+ RosegardenGUIApp::self(), SLOT(slotStop()));
+ connect(notationView, SIGNAL(fastForwardPlayback()),
+ RosegardenGUIApp::self(), SLOT(slotFastforward()));
+ connect(notationView, SIGNAL(rewindPlayback()),
+ RosegardenGUIApp::self(), SLOT(slotRewind()));
+ connect(notationView, SIGNAL(fastForwardPlaybackToEnd()),
+ RosegardenGUIApp::self(), SLOT(slotFastForwardToEnd()));
+ connect(notationView, SIGNAL(rewindPlaybackToBeginning()),
+ RosegardenGUIApp::self(), SLOT(slotRewindToBeginning()));
+ connect(notationView, SIGNAL(panic()),
+ RosegardenGUIApp::self(), SLOT(slotPanic()));
+
+ connect(notationView, SIGNAL(saveFile()),
+ RosegardenGUIApp::self(), SLOT(slotFileSave()));
+ connect(notationView, SIGNAL(jumpPlaybackTo(timeT)),
+ getDocument(), SLOT(slotSetPointerPosition(timeT)));
+ connect(notationView, SIGNAL(openInNotation(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsNotation(std::vector<Segment *>)));
+ connect(notationView, SIGNAL(openInMatrix(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsMatrix(std::vector<Segment *>)));
+ connect(notationView, SIGNAL(openInPercussionMatrix(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsPercussionMatrix(std::vector<Segment *>)));
+ connect(notationView, SIGNAL(openInEventList(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsEventList(std::vector<Segment *>)));
+/* hjj: WHAT DO DO WITH THIS ?
+ connect(notationView, SIGNAL(editMetadata(QString)),
+ this, SLOT(slotEditMetadata(QString)));
+*/
+ connect(notationView, SIGNAL(editTriggerSegment(int)),
+ this, SLOT(slotEditTriggerSegment(int)));
+ connect(notationView, SIGNAL(staffLabelChanged(TrackId, QString)),
+ this, SLOT(slotChangeTrackLabel(TrackId, QString)));
+ connect(notationView, SIGNAL(toggleSolo(bool)),
+ RosegardenGUIApp::self(), SLOT(slotToggleSolo(bool)));
+ connect(notationView, SIGNAL(editTimeSignature(timeT)),
+ RosegardenGUIApp::self(), SLOT(slotEditTempos(timeT)));
+
+ SequenceManager *sM = getDocument()->getSequenceManager();
+
+ connect(sM, SIGNAL(insertableNoteOnReceived(int, int)),
+ notationView, SLOT(slotInsertableNoteOnReceived(int, int)));
+ connect(sM, SIGNAL(insertableNoteOffReceived(int, int)),
+ notationView, SLOT(slotInsertableNoteOffReceived(int, int)));
+
+ connect(notationView, SIGNAL(stepByStepTargetRequested(QObject *)),
+ this, SIGNAL(stepByStepTargetRequested(QObject *)));
+ connect(this, SIGNAL(stepByStepTargetRequested(QObject *)),
+ notationView, SLOT(slotStepByStepTargetRequested(QObject *)));
+ connect(RosegardenGUIApp::self(), SIGNAL(compositionStateUpdate()),
+ notationView, SLOT(slotCompositionStateUpdate()));
+ connect(this, SIGNAL(compositionStateUpdate()),
+ notationView, SLOT(slotCompositionStateUpdate()));
+
+ // Encourage the notation view window to open to the same
+ // interval as the current segment view
+ if (m_trackEditor->getSegmentCanvas()->horizontalScrollBar()->value() > 1) { // don't scroll unless we need to
+ // first find the time at the center of the visible segment canvas
+ int centerX = (int)(m_trackEditor->getSegmentCanvas()->contentsX() +
+ m_trackEditor->getSegmentCanvas()->visibleWidth() / 2);
+ timeT centerSegmentView = m_trackEditor->getRulerScale()->getTimeForX(centerX);
+ // then scroll the notation view to that time, "localized" for the current segment
+ notationView->scrollToTime(centerSegmentView);
+ notationView->updateView();
+ }
+
+ return notationView;
+}
+
+void RosegardenGUIView::slotEditSegmentMatrix(Segment* p)
+{
+ SetWaitCursor waitCursor;
+
+ std::vector<Segment *> segmentsToEdit;
+
+ // unlike notation, if we're calling for this on a particular
+ // segment we don't open all the other selected segments as well
+ // (fine in notation because they're in a single window)
+
+ if (p) {
+ if (p->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(p);
+ }
+ } else {
+ int count = 0;
+ SegmentSelection selection = getSelection();
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() != Segment::Audio) {
+ slotEditSegmentMatrix(*i);
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+ return ;
+ }
+
+ if (segmentsToEdit.empty()) {
+ KMessageBox::sorry(this, i18n("No non-audio segments selected"));
+ return ;
+ }
+
+ slotEditSegmentsMatrix(segmentsToEdit);
+}
+
+void RosegardenGUIView::slotEditSegmentPercussionMatrix(Segment* p)
+{
+ SetWaitCursor waitCursor;
+
+ std::vector<Segment *> segmentsToEdit;
+
+ // unlike notation, if we're calling for this on a particular
+ // segment we don't open all the other selected segments as well
+ // (fine in notation because they're in a single window)
+
+ if (p) {
+ if (p->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(p);
+ }
+ } else {
+ int count = 0;
+ SegmentSelection selection = getSelection();
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() != Segment::Audio) {
+ slotEditSegmentPercussionMatrix(*i);
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+ return ;
+ }
+
+ if (segmentsToEdit.empty()) {
+ KMessageBox::sorry(this, i18n("No non-audio segments selected"));
+ return ;
+ }
+
+ slotEditSegmentsPercussionMatrix(segmentsToEdit);
+}
+
+void RosegardenGUIView::slotEditSegmentsMatrix(std::vector<Segment *> segmentsToEdit)
+{
+ int count = 0;
+ for (std::vector<Segment *>::iterator i = segmentsToEdit.begin();
+ i != segmentsToEdit.end(); ++i) {
+ std::vector<Segment *> tmpvec;
+ tmpvec.push_back(*i);
+ MatrixView *view = createMatrixView(tmpvec, false);
+ if (view) {
+ view->show();
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+}
+
+void RosegardenGUIView::slotEditSegmentsPercussionMatrix(std::vector<Segment *> segmentsToEdit)
+{
+ int count = 0;
+ for (std::vector<Segment *>::iterator i = segmentsToEdit.begin();
+ i != segmentsToEdit.end(); ++i) {
+ std::vector<Segment *> tmpvec;
+ tmpvec.push_back(*i);
+ MatrixView *view = createMatrixView(tmpvec, true);
+ if (view) {
+ view->show();
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+}
+
+MatrixView *
+RosegardenGUIView::createMatrixView(std::vector<Segment *> segmentsToEdit, bool drumMode)
+{
+ MatrixView *matrixView = new MatrixView(getDocument(),
+ segmentsToEdit,
+ this,
+ drumMode);
+
+ // For tempo changes (ugh -- it'd be nicer to make a tempo change
+ // command that could interpret all this stuff from the dialog)
+ //
+ connect(matrixView, SIGNAL(changeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)),
+ RosegardenGUIApp::self(), SLOT(slotChangeTempo(timeT,
+ tempoT,
+ tempoT,
+ TempoDialog::TempoDialogAction)));
+
+ connect(matrixView, SIGNAL(windowActivated()),
+ this, SLOT(slotActiveMainWindowChanged()));
+
+ connect(matrixView, SIGNAL(selectTrack(int)),
+ this, SLOT(slotSelectTrackSegments(int)));
+
+ connect(matrixView, SIGNAL(play()),
+ RosegardenGUIApp::self(), SLOT(slotPlay()));
+ connect(matrixView, SIGNAL(stop()),
+ RosegardenGUIApp::self(), SLOT(slotStop()));
+ connect(matrixView, SIGNAL(fastForwardPlayback()),
+ RosegardenGUIApp::self(), SLOT(slotFastforward()));
+ connect(matrixView, SIGNAL(rewindPlayback()),
+ RosegardenGUIApp::self(), SLOT(slotRewind()));
+ connect(matrixView, SIGNAL(fastForwardPlaybackToEnd()),
+ RosegardenGUIApp::self(), SLOT(slotFastForwardToEnd()));
+ connect(matrixView, SIGNAL(rewindPlaybackToBeginning()),
+ RosegardenGUIApp::self(), SLOT(slotRewindToBeginning()));
+ connect(matrixView, SIGNAL(panic()),
+ RosegardenGUIApp::self(), SLOT(slotPanic()));
+
+ connect(matrixView, SIGNAL(saveFile()),
+ RosegardenGUIApp::self(), SLOT(slotFileSave()));
+ connect(matrixView, SIGNAL(jumpPlaybackTo(timeT)),
+ getDocument(), SLOT(slotSetPointerPosition(timeT)));
+ connect(matrixView, SIGNAL(openInNotation(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsNotation(std::vector<Segment *>)));
+ connect(matrixView, SIGNAL(openInMatrix(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsMatrix(std::vector<Segment *>)));
+ connect(matrixView, SIGNAL(openInEventList(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsEventList(std::vector<Segment *>)));
+ connect(matrixView, SIGNAL(editTriggerSegment(int)),
+ this, SLOT(slotEditTriggerSegment(int)));
+ connect(matrixView, SIGNAL(toggleSolo(bool)),
+ RosegardenGUIApp::self(), SLOT(slotToggleSolo(bool)));
+ connect(matrixView, SIGNAL(editTimeSignature(timeT)),
+ RosegardenGUIApp::self(), SLOT(slotEditTempos(timeT)));
+
+ SequenceManager *sM = getDocument()->getSequenceManager();
+
+ connect(sM, SIGNAL(insertableNoteOnReceived(int, int)),
+ matrixView, SLOT(slotInsertableNoteOnReceived(int, int)));
+ connect(sM, SIGNAL(insertableNoteOffReceived(int, int)),
+ matrixView, SLOT(slotInsertableNoteOffReceived(int, int)));
+
+ connect(matrixView, SIGNAL(stepByStepTargetRequested(QObject *)),
+ this, SIGNAL(stepByStepTargetRequested(QObject *)));
+ connect(this, SIGNAL(stepByStepTargetRequested(QObject *)),
+ matrixView, SLOT(slotStepByStepTargetRequested(QObject *)));
+ connect(RosegardenGUIApp::self(), SIGNAL(compositionStateUpdate()),
+ matrixView, SLOT(slotCompositionStateUpdate()));
+ connect(this, SIGNAL(compositionStateUpdate()),
+ matrixView, SLOT(slotCompositionStateUpdate()));
+ connect(this,
+ SIGNAL(instrumentLevelsChanged(InstrumentId,
+ const LevelInfo &)),
+ matrixView,
+ SLOT(slotInstrumentLevelsChanged(InstrumentId,
+ const LevelInfo &)));
+
+ // Encourage the matrix view window to open to the same
+ // interval as the current segment view
+ if (m_trackEditor->getSegmentCanvas()->horizontalScrollBar()->value() > 1) { // don't scroll unless we need to
+ // first find the time at the center of the visible segment canvas
+ int centerX = (int)(m_trackEditor->getSegmentCanvas()->contentsX());
+ // Seems to work better for matrix view to scroll to left side
+ // + m_trackEditor->getSegmentCanvas()->visibleWidth() / 2);
+ timeT centerSegmentView = m_trackEditor->getRulerScale()->getTimeForX(centerX);
+ // then scroll the notation view to that time, "localized" for the current segment
+ matrixView->scrollToTime(centerSegmentView);
+ matrixView->updateView();
+ }
+
+ return matrixView;
+}
+
+void RosegardenGUIView::slotEditSegmentEventList(Segment *p)
+{
+ SetWaitCursor waitCursor;
+
+ std::vector<Segment *> segmentsToEdit;
+
+ // unlike notation, if we're calling for this on a particular
+ // segment we don't open all the other selected segments as well
+ // (fine in notation because they're in a single window)
+
+ if (p) {
+ if (p->getType() != Segment::Audio) {
+ segmentsToEdit.push_back(p);
+ }
+ } else {
+ int count = 0;
+ SegmentSelection selection = getSelection();
+ for (SegmentSelection::iterator i = selection.begin();
+ i != selection.end(); ++i) {
+ if ((*i)->getType() != Segment::Audio) {
+ slotEditSegmentEventList(*i);
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+ return ;
+ }
+
+ if (segmentsToEdit.empty()) {
+ KMessageBox::sorry(this, i18n("No non-audio segments selected"));
+ return ;
+ }
+
+ slotEditSegmentsEventList(segmentsToEdit);
+}
+
+void RosegardenGUIView::slotEditSegmentsEventList(std::vector<Segment *> segmentsToEdit)
+{
+ int count = 0;
+ for (std::vector<Segment *>::iterator i = segmentsToEdit.begin();
+ i != segmentsToEdit.end(); ++i) {
+ std::vector<Segment *> tmpvec;
+ tmpvec.push_back(*i);
+ EventView *view = createEventView(tmpvec);
+ if (view) {
+ view->show();
+ if (++count == maxEditorsToOpen)
+ break;
+ }
+ }
+}
+
+void RosegardenGUIView::slotEditTriggerSegment(int id)
+{
+ SetWaitCursor waitCursor;
+
+ std::vector<Segment *> segmentsToEdit;
+
+ Segment *s = getDocument()->getComposition().getTriggerSegment(id);
+
+ if (s) {
+ segmentsToEdit.push_back(s);
+ } else {
+ return ;
+ }
+
+ slotEditSegmentsEventList(segmentsToEdit);
+}
+
+void RosegardenGUIView::slotSegmentAutoSplit(Segment *segment)
+{
+ AudioSplitDialog aSD(this, segment, getDocument());
+
+ if (aSD.exec() == QDialog::Accepted) {
+ KCommand *command =
+ new AudioSegmentAutoSplitCommand(getDocument(),
+ segment, aSD.getThreshold());
+ slotAddCommandToHistory(command);
+ }
+}
+
+void RosegardenGUIView::slotEditSegmentAudio(Segment *segment)
+{
+ std::cout << "RosegardenGUIView::slotEditSegmentAudio() - "
+ << "starting external audio editor" << std::endl;
+
+ KConfig* config = kapp->config();
+ config->setGroup(GeneralOptionsConfigGroup);
+
+ QString application = config->readEntry("externalaudioeditor", "");
+
+ if (application == "") {
+ application = AudioConfigurationPage::getBestAvailableAudioEditor();
+ }
+
+ QStringList splitCommand = QStringList::split(" ", application);
+
+ if (splitCommand.size() == 0) {
+
+ std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
+ << "external editor \"" << application.data()
+ << "\" not found" << std::endl;
+
+ KMessageBox::sorry(this,
+ i18n("You've not yet defined an audio editor for Rosegarden to use.\nSee Settings -> Configure Rosegarden -> Audio."));
+
+ return ;
+ }
+
+ QFileInfo *appInfo = new QFileInfo(splitCommand[0]);
+ if (appInfo->exists() == false || appInfo->isExecutable() == false) {
+ std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
+ << "can't execute \"" << splitCommand[0] << "\""
+ << std::endl;
+ return;
+ }
+
+ AudioFile *aF = getDocument()->getAudioFileManager().
+ getAudioFile(segment->getAudioFileId());
+ if (aF == 0) {
+ std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
+ << "can't find audio file" << std::endl;
+ return ;
+ }
+
+ // wait cursor
+ QApplication::setOverrideCursor(QCursor(Qt::waitCursor));
+
+ // Prepare the process
+ //
+ KProcess *process = new KProcess();
+ (*process) << splitCommand;
+ (*process) << QString(aF->getFilename().c_str());
+
+ // Start it
+ //
+ if (!process->start()) {
+ std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
+ << "can't start external editor" << std::endl;
+ }
+
+ // restore cursor
+ QApplication::restoreOverrideCursor();
+
+}
+
+void RosegardenGUIView::setZoomSize(double size)
+{
+ m_rulerScale->setUnitsPerPixel(size);
+
+ double duration44 = TimeSignature(4, 4).getBarDuration();
+
+ double xScale = duration44 / (size * barWidth44);
+ RG_DEBUG << "RosegardenGUIView::setZoomSize - xScale = " << xScale << endl;
+
+ m_trackEditor->slotSetPointerPosition
+ (getDocument()->getComposition().getPosition());
+
+ m_trackEditor->getSegmentCanvas()->clearSegmentRectsCache(true);
+ m_trackEditor->getSegmentCanvas()->slotUpdateSize();
+ m_trackEditor->getSegmentCanvas()->slotUpdateSegmentsDrawBuffer();
+
+ if (m_trackEditor->getTempoRuler()) {
+ m_trackEditor->getTempoRuler()->repaint();
+ }
+
+ if (m_trackEditor->getChordNameRuler()) {
+ m_trackEditor->getChordNameRuler()->repaint();
+ }
+
+ if (m_trackEditor->getTopStandardRuler()) {
+ m_trackEditor->getTopStandardRuler()->repaint();
+ }
+
+ if (m_trackEditor->getBottomStandardRuler()) {
+ m_trackEditor->getBottomStandardRuler()->repaint();
+ }
+}
+
+void RosegardenGUIView::slotSelectTrackSegments(int trackId)
+{
+ // update the instrument parameter box
+ Composition &comp = getDocument()->getComposition();
+ Track *track = comp.getTrackById(trackId);
+
+ if (track == 0)
+ return ;
+
+ // Show the selection on the track buttons. Find the position.
+ //
+ m_trackEditor->getTrackButtons()->selectLabel(track->getPosition());
+ m_trackEditor->slotScrollToTrack(track->getPosition());
+
+ SegmentSelection segments;
+
+ for (Composition::iterator i =
+ getDocument()->getComposition().begin();
+ i != getDocument()->getComposition().end(); i++) {
+ if (((int)(*i)->getTrack()) == trackId)
+ segments.insert(*i);
+ }
+
+ // Store the selected Track in the Composition
+ //
+ comp.setSelectedTrack(trackId);
+
+ m_trackParameterBox->slotSelectedTrackChanged();
+
+ slotUpdateInstrumentParameterBox(comp.getTrackById(trackId)->
+ getInstrument());
+
+
+ slotPropagateSegmentSelection(segments);
+
+ // inform
+ emit segmentsSelected(segments);
+ emit compositionStateUpdate();
+}
+
+void RosegardenGUIView::slotPropagateSegmentSelection(const SegmentSelection &segments)
+{
+ // Send this signal to the GUI to activate the correct tool
+ // on the toolbar so that we have a SegmentSelector object
+ // to write the Segments into
+ //
+ if (!segments.empty()) {
+ emit activateTool(SegmentSelector::ToolName);
+ }
+
+ // Send the segment list even if it's empty as we
+ // use that to clear any current selection
+ //
+ m_trackEditor->getSegmentCanvas()->slotSelectSegments(segments);
+
+ // update the segment parameter box
+ m_segmentParameterBox->useSegments(segments);
+
+ if (!segments.empty()) {
+ emit stateChange("have_selection", true);
+ if (!segments.hasNonAudioSegment()) {
+ emit stateChange("audio_segment_selected", true);
+ }
+ } else {
+ emit stateChange("have_selection", false);
+ }
+}
+
+void RosegardenGUIView::slotSelectAllSegments()
+{
+ SegmentSelection segments;
+
+ InstrumentId instrument = 0;
+ bool haveInstrument = false;
+ bool multipleInstruments = false;
+
+ Composition &comp = getDocument()->getComposition();
+
+ for (Composition::iterator i = comp.begin(); i != comp.end(); ++i) {
+
+ InstrumentId myInstrument =
+ comp.getTrackById((*i)->getTrack())->getInstrument();
+
+ if (haveInstrument) {
+ if (myInstrument != instrument) {
+ multipleInstruments = true;
+ }
+ } else {
+ instrument = myInstrument;
+ haveInstrument = true;
+ }
+
+ segments.insert(*i);
+ }
+
+ // Send this signal to the GUI to activate the correct tool
+ // on the toolbar so that we have a SegmentSelector object
+ // to write the Segments into
+ //
+ if (!segments.empty()) {
+ emit activateTool(SegmentSelector::ToolName);
+ }
+
+ // Send the segment list even if it's empty as we
+ // use that to clear any current selection
+ //
+ m_trackEditor->getSegmentCanvas()->slotSelectSegments(segments);
+
+ // update the segment parameter box
+ m_segmentParameterBox->useSegments(segments);
+
+ // update the instrument parameter box
+ if (haveInstrument && !multipleInstruments) {
+ slotUpdateInstrumentParameterBox(instrument);
+ } else {
+ m_instrumentParameterBox->useInstrument(0);
+ }
+
+ //!!! similarly, how to set no selected track?
+ //comp.setSelectedTrack(trackId);
+
+ if (!segments.empty()) {
+ emit stateChange("have_selection", true);
+ if (!segments.hasNonAudioSegment()) {
+ emit stateChange("audio_segment_selected", true);
+ }
+ } else {
+ emit stateChange("have_selection", false);
+ }
+
+ // inform
+ //!!! inform what? is this signal actually used?
+ emit segmentsSelected(segments);
+}
+
+void RosegardenGUIView::slotUpdateInstrumentParameterBox(int id)
+{
+ Studio &studio = getDocument()->getStudio();
+ Instrument *instrument = studio.getInstrumentById(id);
+ Composition &comp = getDocument()->getComposition();
+
+ Track *track = comp.getTrackById(comp.getSelectedTrack());
+
+ // Reset the instrument
+ //
+ m_instrumentParameterBox->useInstrument(instrument);
+
+ // Then do this instrument/track fiddling
+ //
+ /*
+ if (track && instrument &&
+ instrument->getType() == Instrument::Audio)
+ {
+ // Set the mute status
+ m_instrumentParameterBox->setMute(track->isMuted());
+
+ // Set the record track
+ m_instrumentParameterBox->setRecord(
+ track->getId() == comp.getRecordTrack());
+
+ // Set solo
+ m_instrumentParameterBox->setSolo(
+ comp.isSolo() && (track->getId() == comp.getSelectedTrack()));
+ }
+ */
+ emit checkTrackAssignments();
+}
+
+void RosegardenGUIView::showVisuals(const MappedEvent *mE)
+{
+ double valueLeft = ((double)mE->getData1()) / 127.0;
+ double valueRight = ((double)mE->getData2()) / 127.0;
+
+ if (mE->getType() == MappedEvent::AudioLevel) {
+
+ // Send to the high sensitivity instrument parameter box
+ // (if any)
+ //
+ if (m_instrumentParameterBox->getSelectedInstrument() &&
+ mE->getInstrument() ==
+ m_instrumentParameterBox->getSelectedInstrument()->getId()) {
+ float dBleft = AudioLevel::fader_to_dB
+ (mE->getData1(), 127, AudioLevel::LongFader);
+ float dBright = AudioLevel::fader_to_dB
+ (mE->getData2(), 127, AudioLevel::LongFader);
+
+ m_instrumentParameterBox->setAudioMeter(dBleft, dBright,
+ AudioLevel::DB_FLOOR,
+ AudioLevel::DB_FLOOR);
+ }
+
+ // Don't always send all audio levels so we don't
+ // get vu meter flickering on track meters
+ //
+ if (valueLeft < 0.05 && valueRight < 0.05)
+ return ;
+
+ } else if (mE->getType() != MappedEvent::MidiNote)
+ return ;
+
+ m_trackEditor->getTrackButtons()->
+ slotSetMetersByInstrument((valueLeft + valueRight) / 2,
+ mE->getInstrument());
+
+}
+
+void
+RosegardenGUIView::updateMeters(SequencerMapper *mapper)
+{
+ const int unknownState = 0, oldState = 1, newState = 2;
+
+ typedef std::map<InstrumentId, int> StateMap;
+ static StateMap states;
+ static StateMap recStates;
+
+ typedef std::map<InstrumentId, LevelInfo> LevelMap;
+ static LevelMap levels;
+ static LevelMap recLevels;
+
+ for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
+ i->second = unknownState;
+ }
+ for (StateMap::iterator i = recStates.begin(); i != recStates.end(); ++i) {
+ i->second = unknownState;
+ }
+
+ for (Composition::trackcontainer::iterator i =
+ getDocument()->getComposition().getTracks().begin();
+ i != getDocument()->getComposition().getTracks().end(); ++i) {
+
+ Track *track = i->second;
+ if (!track)
+ continue;
+
+ InstrumentId instrumentId = track->getInstrument();
+
+ if (states[instrumentId] == unknownState) {
+ bool isNew = mapper->getInstrumentLevel(instrumentId,
+ levels[instrumentId]);
+ states[instrumentId] = (isNew ? newState : oldState);
+ }
+
+ if (recStates[instrumentId] == unknownState) {
+ bool isNew = mapper->getInstrumentRecordLevel(instrumentId,
+ recLevels[instrumentId]);
+ recStates[instrumentId] = (isNew ? newState : oldState);
+ }
+
+ if (states[instrumentId] == oldState &&
+ recStates[instrumentId] == oldState)
+ continue;
+
+ Instrument *instrument =
+ getDocument()->getStudio().getInstrumentById(instrumentId);
+ if (!instrument)
+ continue;
+
+ // This records the level of this instrument, not neccessarily
+ // caused by notes on this particular track.
+ LevelInfo &info = levels[instrumentId];
+ LevelInfo &recInfo = recLevels[instrumentId];
+
+ if (instrument->getType() == Instrument::Audio ||
+ instrument->getType() == Instrument::SoftSynth) {
+
+ float dBleft = AudioLevel::DB_FLOOR;
+ float dBright = AudioLevel::DB_FLOOR;
+ float recDBleft = AudioLevel::DB_FLOOR;
+ float recDBright = AudioLevel::DB_FLOOR;
+
+ bool toSet = false;
+
+ if (states[instrumentId] == newState &&
+ (getDocument()->getSequenceManager()->getTransportStatus()
+ != STOPPED)) {
+
+ if (info.level != 0 || info.levelRight != 0) {
+ dBleft = AudioLevel::fader_to_dB
+ (info.level, 127, AudioLevel::LongFader);
+ dBright = AudioLevel::fader_to_dB
+ (info.levelRight, 127, AudioLevel::LongFader);
+ }
+ toSet = true;
+ m_trackEditor->getTrackButtons()->slotSetTrackMeter
+ ((info.level + info.levelRight) / 254.0, track->getPosition());
+ }
+
+ if (recStates[instrumentId] == newState &&
+ instrument->getType() == Instrument::Audio &&
+ (getDocument()->getSequenceManager()->getTransportStatus()
+ != PLAYING)) {
+
+ if (recInfo.level != 0 || recInfo.levelRight != 0) {
+ recDBleft = AudioLevel::fader_to_dB
+ (recInfo.level, 127, AudioLevel::LongFader);
+ recDBright = AudioLevel::fader_to_dB
+ (recInfo.levelRight, 127, AudioLevel::LongFader);
+ }
+ toSet = true;
+ }
+
+ if (toSet &&
+ m_instrumentParameterBox->getSelectedInstrument() &&
+ instrument->getId() ==
+ m_instrumentParameterBox->getSelectedInstrument()->getId()) {
+
+ m_instrumentParameterBox->setAudioMeter(dBleft, dBright,
+ recDBleft, recDBright);
+ }
+
+ } else {
+ // Not audio or softsynth
+ if (info.level == 0)
+ continue;
+
+ if (getDocument()->getSequenceManager()->getTransportStatus()
+ != STOPPED) {
+
+ // The information in 'info' is specific for this instrument, not
+ // for this track.
+ //m_trackEditor->getTrackButtons()->slotSetTrackMeter
+ // (info.level / 127.0, track->getPosition());
+ m_trackEditor->getTrackButtons()->slotSetMetersByInstrument
+ (info.level / 127.0, instrumentId);
+ }
+ }
+ }
+
+ for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
+ if (i->second == newState) {
+ emit instrumentLevelsChanged(i->first, levels[i->first]);
+ }
+ }
+}
+
+void
+RosegardenGUIView::updateMonitorMeters(SequencerMapper *mapper)
+{
+ Instrument *instrument =
+ m_instrumentParameterBox->getSelectedInstrument();
+ if (!instrument ||
+ (instrument->getType() != Instrument::Audio))
+ return ;
+
+ LevelInfo level;
+ if (!mapper->getInstrumentRecordLevel(instrument->getId(), level))
+ return ;
+
+ float dBleft = AudioLevel::fader_to_dB
+ (level.level, 127, AudioLevel::LongFader);
+ float dBright = AudioLevel::fader_to_dB
+ (level.levelRight, 127, AudioLevel::LongFader);
+
+ m_instrumentParameterBox->setAudioMeter
+ (AudioLevel::DB_FLOOR, AudioLevel::DB_FLOOR,
+ dBleft, dBright);
+}
+
+void
+RosegardenGUIView::slotSelectedSegments(const SegmentSelection &segments)
+{
+ // update the segment parameter box
+ m_segmentParameterBox->useSegments(segments);
+
+ if (!segments.empty()) {
+ emit stateChange("have_selection", true);
+ if (!segments.hasNonAudioSegment())
+ emit stateChange("audio_segment_selected", true);
+ } else {
+ emit stateChange("have_selection", false);
+ }
+
+ emit segmentsSelected(segments);
+}
+
+void RosegardenGUIView::slotShowRulers(bool v)
+{
+ if (v) {
+ m_trackEditor->getTopStandardRuler()->getLoopRuler()->show();
+ m_trackEditor->getBottomStandardRuler()->getLoopRuler()->show();
+ } else {
+ m_trackEditor->getTopStandardRuler()->getLoopRuler()->hide();
+ m_trackEditor->getBottomStandardRuler()->getLoopRuler()->hide();
+ }
+}
+
+void RosegardenGUIView::slotShowTempoRuler(bool v)
+{
+ if (v) {
+ m_trackEditor->getTempoRuler()->show();
+ } else {
+ m_trackEditor->getTempoRuler()->hide();
+ }
+}
+
+void RosegardenGUIView::slotShowChordNameRuler(bool v)
+{
+ if (v) {
+ m_trackEditor->getChordNameRuler()->setStudio(&getDocument()->getStudio());
+ m_trackEditor->getChordNameRuler()->show();
+ } else {
+ m_trackEditor->getChordNameRuler()->hide();
+ }
+}
+
+void RosegardenGUIView::slotShowPreviews(bool v)
+{
+ m_trackEditor->getSegmentCanvas()->setShowPreviews(v);
+ m_trackEditor->getSegmentCanvas()->slotUpdateSegmentsDrawBuffer();
+}
+
+void RosegardenGUIView::slotShowSegmentLabels(bool v)
+{
+ m_trackEditor->getSegmentCanvas()->setShowSegmentLabels(v);
+ m_trackEditor->getSegmentCanvas()->slotUpdateSegmentsDrawBuffer();
+}
+
+void RosegardenGUIView::slotAddTracks(unsigned int nbTracks,
+ InstrumentId id, int pos)
+{
+ RG_DEBUG << "RosegardenGUIView::slotAddTracks(" << nbTracks << ", " << pos << ")" << endl;
+ m_trackEditor->slotAddTracks(nbTracks, id, pos);
+}
+
+void RosegardenGUIView::slotDeleteTracks(
+ std::vector<TrackId> tracks)
+{
+ RG_DEBUG << "RosegardenGUIView::slotDeleteTracks - "
+ << "deleting " << tracks.size() << " tracks"
+ << endl;
+
+ m_trackEditor->slotDeleteTracks(tracks);
+}
+
+MultiViewCommandHistory*
+RosegardenGUIView::getCommandHistory()
+{
+ return getDocument()->getCommandHistory();
+}
+
+void
+RosegardenGUIView::slotAddCommandToHistory(KCommand *command)
+{
+ getCommandHistory()->addCommand(command);
+}
+
+void
+RosegardenGUIView::slotChangeInstrumentLabel(InstrumentId id,
+ QString label)
+{
+ m_trackEditor->getTrackButtons()->changeInstrumentLabel(id, label);
+}
+
+void
+RosegardenGUIView::slotChangeTrackLabel(TrackId id,
+ QString label)
+{
+ m_trackEditor->getTrackButtons()->changeTrackLabel(id, label);
+}
+
+void
+RosegardenGUIView::slotAddAudioSegment(AudioFileId audioId,
+ TrackId trackId,
+ timeT position,
+ const RealTime &startTime,
+ const RealTime &endTime)
+{
+ AudioSegmentInsertCommand *command =
+ new AudioSegmentInsertCommand(getDocument(),
+ trackId,
+ position,
+ audioId,
+ startTime,
+ endTime);
+ slotAddCommandToHistory(command);
+
+ Segment *newSegment = command->getNewSegment();
+ if (newSegment) {
+ SegmentSelection selection;
+ selection.insert(newSegment);
+ slotPropagateSegmentSelection(selection);
+ emit segmentsSelected(selection);
+ }
+}
+
+void
+RosegardenGUIView::slotAddAudioSegmentCurrentPosition(AudioFileId audioFileId,
+ const RealTime &startTime,
+ const RealTime &endTime)
+{
+ Composition &comp = getDocument()->getComposition();
+
+ AudioSegmentInsertCommand *command =
+ new AudioSegmentInsertCommand(getDocument(),
+ comp.getSelectedTrack(),
+ comp.getPosition(),
+ audioFileId,
+ startTime,
+ endTime);
+ slotAddCommandToHistory(command);
+
+ Segment *newSegment = command->getNewSegment();
+ if (newSegment) {
+ SegmentSelection selection;
+ selection.insert(newSegment);
+ slotPropagateSegmentSelection(selection);
+ emit segmentsSelected(selection);
+ }
+}
+
+void
+RosegardenGUIView::slotAddAudioSegmentDefaultPosition(AudioFileId audioFileId,
+ const RealTime &startTime,
+ const RealTime &endTime)
+{
+ // Add at current track if it's an audio track, otherwise at first
+ // empty audio track if there is one, otherwise at first audio track.
+ // This behaviour should be of no interest to proficient users (who
+ // should have selected the right track already, or be using drag-
+ // and-drop) but it should save beginners from inserting an audio
+ // segment and being quite unable to work out why it won't play
+
+ Composition &comp = getDocument()->getComposition();
+ Studio &studio = getDocument()->getStudio();
+
+ TrackId currentTrackId = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(currentTrackId);
+
+ if (track) {
+ InstrumentId ii = track->getInstrument();
+ Instrument *instrument = studio.getInstrumentById(ii);
+
+ if (instrument &&
+ instrument->getType() == Instrument::Audio) {
+ slotAddAudioSegment(audioFileId, currentTrackId,
+ comp.getPosition(), startTime, endTime);
+ return ;
+ }
+ }
+
+ // current track is not an audio track, find a more suitable one
+
+ TrackId bestSoFar = currentTrackId;
+
+ for (Composition::trackcontainer::const_iterator
+ ti = comp.getTracks().begin();
+ ti != comp.getTracks().end(); ++ti) {
+
+ InstrumentId ii = ti->second->getInstrument();
+ Instrument *instrument = studio.getInstrumentById(ii);
+
+ if (instrument &&
+ instrument->getType() == Instrument::Audio) {
+
+ if (bestSoFar == currentTrackId)
+ bestSoFar = ti->first;
+ bool haveSegment = false;
+
+ for (Composition::segmentcontainer::const_iterator si =
+ comp.getSegments().begin();
+ si != comp.getSegments().end(); ++si) {
+ if ((*si)->getTrack() == ti->first) {
+ // there's a segment on this track
+ haveSegment = true;
+ break;
+ }
+ }
+
+ if (!haveSegment) { // perfect
+ slotAddAudioSegment(audioFileId, ti->first,
+ comp.getPosition(), startTime, endTime);
+ return ;
+ }
+ }
+ }
+
+ slotAddAudioSegment(audioFileId, bestSoFar,
+ comp.getPosition(), startTime, endTime);
+ return ;
+}
+
+void
+RosegardenGUIView::slotDroppedNewAudio(QString audioDesc)
+{
+ QTextIStream s(&audioDesc);
+
+ QString url;
+ int trackId;
+ timeT time;
+ url = s.readLine();
+ s >> trackId;
+ s >> time;
+
+ std::cerr << "RosegardenGUIView::slotDroppedNewAudio: url " << url << ", trackId " << trackId << ", time " << time << std::endl;
+
+ RosegardenGUIApp *app = RosegardenGUIApp::self();
+ AudioFileManager &aFM = getDocument()->getAudioFileManager();
+
+ AudioFileId audioFileId = 0;
+
+ int sampleRate = 0;
+ if (getDocument()->getSequenceManager()) {
+ sampleRate = getDocument()->getSequenceManager()->getSampleRate();
+ }
+
+ KURL kurl(url);
+ if (!kurl.isLocalFile()) {
+ if (!RosegardenGUIApp::self()->testAudioPath("importing a remote audio file")) return;
+ } else if (aFM.fileNeedsConversion(qstrtostr(kurl.path()), sampleRate)) {
+ if (!RosegardenGUIApp::self()->testAudioPath("importing an audio file that needs to be converted or resampled")) return;
+ }
+
+ ProgressDialog progressDlg(i18n("Adding audio file..."),
+ 100,
+ this);
+
+ CurrentProgressDialog::set(&progressDlg);
+ progressDlg.progressBar()->hide();
+ progressDlg.show();
+
+ // Connect the progress dialog
+ //
+ connect(&aFM, SIGNAL(setProgress(int)),
+ progressDlg.progressBar(), SLOT(setValue(int)));
+ connect(&aFM, SIGNAL(setOperationName(QString)),
+ &progressDlg, SLOT(slotSetOperationName(QString)));
+ connect(&progressDlg, SIGNAL(cancelClicked()),
+ &aFM, SLOT(slotStopImport()));
+
+ try {
+ audioFileId = aFM.importURL(kurl, sampleRate);
+ } catch (AudioFileManager::BadAudioPathException e) {
+ CurrentProgressDialog::freeze();
+ QString errorString = i18n("Can't add dropped file. ") + strtoqstr(e.getMessage());
+ KMessageBox::sorry(this, errorString);
+ return ;
+ } catch (SoundFile::BadSoundFileException e) {
+ CurrentProgressDialog::freeze();
+ QString errorString = i18n("Can't add dropped file. ") + strtoqstr(e.getMessage());
+ KMessageBox::sorry(this, errorString);
+ return ;
+ }
+
+ disconnect(&progressDlg, SIGNAL(cancelClicked()),
+ &aFM, SLOT(slotStopImport()));
+ connect(&progressDlg, SIGNAL(cancelClicked()),
+ &aFM, SLOT(slotStopPreview()));
+ progressDlg.progressBar()->show();
+ progressDlg.slotSetOperationName(i18n("Generating audio preview..."));
+
+ try {
+ aFM.generatePreview(audioFileId);
+ } catch (Exception e) {
+ CurrentProgressDialog::freeze();
+ QString message = strtoqstr(e.getMessage()) + "\n\n" +
+ i18n("Try copying this file to a directory where you have write permission and re-add it");
+ KMessageBox::information(this, message);
+ //return false;
+ }
+
+ disconnect(&progressDlg, SIGNAL(cancelClicked()),
+ &aFM, SLOT(slotStopPreview()));
+
+ // add the file at the sequencer
+ emit addAudioFile(audioFileId);
+
+ // Now fetch file details
+ //
+ AudioFile *aF = aFM.getAudioFile(audioFileId);
+
+ if (aF) {
+ slotAddAudioSegment(audioFileId, trackId, time,
+ RealTime(0, 0), aF->getLength());
+
+ RG_DEBUG << "RosegardenGUIView::slotDroppedNewAudio("
+ << "file = " << url
+ << ", trackid = " << trackId
+ << ", time = " << time << endl;
+ }
+}
+
+void
+RosegardenGUIView::slotDroppedAudio(QString audioDesc)
+{
+ QTextIStream s(&audioDesc);
+
+ AudioFileId audioFileId;
+ TrackId trackId;
+ timeT position;
+ RealTime startTime, endTime;
+
+ // read the audio info
+ s >> audioFileId;
+ s >> trackId;
+ s >> position;
+ s >> startTime.sec;
+ s >> startTime.nsec;
+ s >> endTime.sec;
+ s >> endTime.nsec;
+
+ RG_DEBUG << "RosegardenGUIView::slotDroppedAudio("
+ //<< audioDesc
+ << ") : audioFileId = " << audioFileId
+ << " - trackId = " << trackId
+ << " - position = " << position
+ << " - startTime.sec = " << startTime.sec
+ << " - startTime.nsec = " << startTime.nsec
+ << " - endTime.sec = " << endTime.sec
+ << " - endTime.nsec = " << endTime.nsec
+ << endl;
+
+ slotAddAudioSegment(audioFileId, trackId, position, startTime, endTime);
+}
+
+void
+RosegardenGUIView::slotSetMuteButton(TrackId track, bool value)
+{
+ RG_DEBUG << "RosegardenGUIView::slotSetMuteButton - track id = " << track
+ << ", value = " << value << endl;
+
+ m_trackEditor->getTrackButtons()->setMuteButton(track, value);
+ Track *trackObj = getDocument()->
+ getComposition().getTrackById(track);
+ /*
+ // to fix 739544
+ if (m_instrumentParameterBox->getSelectedInstrument() &&
+ m_instrumentParameterBox->getSelectedInstrument()->getId() ==
+ trackObj->getInstrument())
+ {
+ m_instrumentParameterBox->setMute(value);
+ }
+ */
+ // set the value in the composition
+ trackObj->setMuted(value);
+
+ getDocument()->slotDocumentModified(); // set the modification flag
+
+}
+
+void
+RosegardenGUIView::slotSetMute(InstrumentId id, bool value)
+{
+ RG_DEBUG << "RosegardenGUIView::slotSetMute - "
+ << "id = " << id
+ << ",value = " << value << endl;
+
+ Composition &comp = getDocument()->getComposition();
+ Composition::trackcontainer &tracks = comp.getTracks();
+ Composition::trackiterator it;
+
+ for (it = tracks.begin(); it != tracks.end(); ++it) {
+ if ((*it).second->getInstrument() == id)
+ slotSetMuteButton((*it).second->getId(), value);
+ }
+
+}
+
+void
+RosegardenGUIView::slotSetRecord(InstrumentId id, bool value)
+{
+ RG_DEBUG << "RosegardenGUIView::slotSetRecord - "
+ << "id = " << id
+ << ",value = " << value << endl;
+ /*
+ // IPB
+ //
+ m_instrumentParameterBox->setRecord(value);
+ */
+ Composition &comp = getDocument()->getComposition();
+ Composition::trackcontainer &tracks = comp.getTracks();
+ Composition::trackiterator it;
+#ifdef NOT_DEFINED
+
+ for (it = tracks.begin(); it != tracks.end(); ++it) {
+ if (comp.getSelectedTrack() == (*it).second->getId()) {
+ //!!! MTR m_trackEditor->getTrackButtons()->
+ // setRecordTrack((*it).second->getPosition());
+ //!!! MTR is this needed? I think probably not
+ slotUpdateInstrumentParameterBox((*it).second->getInstrument());
+ }
+ }
+#endif
+ Studio &studio = getDocument()->getStudio();
+ Instrument *instr = studio.getInstrumentById(id);
+}
+
+void
+RosegardenGUIView::slotSetSolo(InstrumentId id, bool value)
+{
+ RG_DEBUG << "RosegardenGUIView::slotSetSolo - "
+ << "id = " << id
+ << ",value = " << value << endl;
+
+ emit toggleSolo(value);
+}
+
+void
+RosegardenGUIView::slotUpdateRecordingSegment(Segment *segment,
+ timeT )
+{
+ // We're only interested in this on the first call per recording segment,
+ // when we possibly create a view for it
+ static Segment *lastRecordingSegment = 0;
+
+ if (segment == lastRecordingSegment)
+ return ;
+ lastRecordingSegment = segment;
+
+ KConfig* config = kapp->config();
+ config->setGroup(GeneralOptionsConfigGroup);
+
+ int tracking = config->readUnsignedNumEntry("recordtracking", 0);
+ if (tracking != 1)
+ return ;
+
+ RG_DEBUG << "RosegardenGUIView::slotUpdateRecordingSegment: segment is " << segment << ", lastRecordingSegment is " << lastRecordingSegment << ", opening a new view" << endl;
+
+ std::vector<Segment *> segments;
+ segments.push_back(segment);
+
+ NotationView *view = createNotationView(segments);
+ if (!view)
+ return ;
+
+ /* signal no longer exists
+ QObject::connect
+ (getDocument(), SIGNAL(recordingSegmentUpdated(Segment *, timeT)),
+ view, SLOT(slotUpdateRecordingSegment(Segment *, timeT)));
+ */
+
+ view->show();
+}
+
+void
+RosegardenGUIView::slotSynchroniseWithComposition()
+{
+ // Track buttons
+ //
+ m_trackEditor->getTrackButtons()->slotSynchroniseWithComposition();
+
+ // Update all IPBs
+ //
+ Composition &comp = getDocument()->getComposition();
+ Track *track = comp.getTrackById(comp.getSelectedTrack());
+ slotUpdateInstrumentParameterBox(track->getInstrument());
+
+ m_instrumentParameterBox->slotUpdateAllBoxes();
+}
+
+void
+RosegardenGUIView::windowActivationChange(bool)
+{
+ if (isActiveWindow()) {
+ slotActiveMainWindowChanged(this);
+ }
+}
+
+void
+RosegardenGUIView::slotActiveMainWindowChanged(const QWidget *w)
+{
+ m_lastActiveMainWindow = w;
+}
+
+void
+RosegardenGUIView::slotActiveMainWindowChanged()
+{
+ const QWidget *w = dynamic_cast<const QWidget *>(sender());
+ if (w)
+ slotActiveMainWindowChanged(w);
+}
+
+void
+RosegardenGUIView::slotControllerDeviceEventReceived(MappedEvent *e)
+{
+ RG_DEBUG << "Controller device event received - send to " << (void *)m_lastActiveMainWindow << " (I am " << this << ")" << endl;
+
+ //!!! So, what _should_ we do with these?
+
+ // -- external controller that sends e.g. volume control for each
+ // of a number of channels -> if mixer present, use control to adjust
+ // tracks on mixer
+
+ // -- external controller that sends e.g. separate controllers on
+ // the same channel for adjusting various parameters -> if IPB
+ // visible, adjust it. Should we use the channel to select the
+ // track? maybe as an option
+
+ // do we actually need the last active main window for either of
+ // these? -- yes, to determine whether to send to mixer or to IPB
+ // in the first place. Send to audio mixer if active, midi mixer
+ // if active, plugin dialog if active, otherwise keep it for
+ // ourselves for the IPB. But, we'll do that by having the edit
+ // views pass it back to us.
+
+ // -- then we need to send back out to device.
+
+ //!!! special cases: controller 81 received by any window ->
+ // select window 0->main, 1->audio mix, 2->midi mix
+
+ //!!! controller 82 received by main window -> select track
+
+ //!!! these obviously should be configurable
+
+ if (e->getType() == MappedEvent::MidiController) {
+
+ if (e->getData1() == 81) {
+
+ // select window
+ int window = e->getData2();
+
+ if (window < 10) { // me
+
+ show();
+ raise();
+ setActiveWindow();
+
+ } else if (window < 20) {
+
+ RosegardenGUIApp::self()->slotOpenAudioMixer();
+
+ } else if (window < 30) {
+
+ RosegardenGUIApp::self()->slotOpenMidiMixer();
+ }
+ }
+ }
+
+ emit controllerDeviceEventReceived(e, m_lastActiveMainWindow);
+}
+
+void
+RosegardenGUIView::slotControllerDeviceEventReceived(MappedEvent *e, const void *preferredCustomer)
+{
+ if (preferredCustomer != this)
+ return ;
+ RG_DEBUG << "RosegardenGUIView::slotControllerDeviceEventReceived: this one's for me" << endl;
+ raise();
+
+ RG_DEBUG << "Event is type: " << int(e->getType()) << ", channel " << int(e->getRecordedChannel()) << ", data1 " << int(e->getData1()) << ", data2 " << int(e->getData2()) << endl;
+
+ Composition &comp = getDocument()->getComposition();
+ Studio &studio = getDocument()->getStudio();
+
+ TrackId currentTrackId = comp.getSelectedTrack();
+ Track *track = comp.getTrackById(currentTrackId);
+
+ // If the event is a control change on channel n, then (if
+ // follow-channel is on) switch to the nth track of the same type
+ // as the current track -- or the first track of the given
+ // channel?, and set the control appropriately. Any controls in
+ // IPB are supported for a MIDI device plus program and bank; only
+ // volume and pan are supported for audio/synth devices.
+ //!!! complete this
+
+ if (e->getType() != MappedEvent::MidiController) {
+
+ if (e->getType() == MappedEvent::MidiProgramChange) {
+ int program = e->getData1();
+ if (!track)
+ return ;
+ InstrumentId ii = track->getInstrument();
+ Instrument *instrument = studio.getInstrumentById(ii);
+ if (!instrument)
+ return ;
+ instrument->setProgramChange(program);
+ emit instrumentParametersChanged(ii);
+ }
+ return ;
+ }
+
+ unsigned int channel = e->getRecordedChannel();
+ MidiByte controller = e->getData1();
+ MidiByte value = e->getData2();
+
+ if (controller == 82) { //!!! magic select-track controller
+ int tracks = comp.getNbTracks();
+ Track *track = comp.getTrackByPosition(value * tracks / 127);
+ if (track) {
+ slotSelectTrackSegments(track->getId());
+ }
+ return ;
+ }
+
+ if (!track)
+ return ;
+
+ InstrumentId ii = track->getInstrument();
+ Instrument *instrument = studio.getInstrumentById(ii);
+
+ if (!instrument)
+ return ;
+
+ switch (instrument->getType()) {
+
+ case Instrument::Midi: {
+ MidiDevice *md = dynamic_cast<MidiDevice *>
+ (instrument->getDevice());
+ if (!md) {
+ std::cerr << "WARNING: MIDI instrument has no MIDI device in slotControllerDeviceEventReceived" << std::endl;
+ return ;
+ }
+
+ //!!! we need a central clearing house for these changes,
+ // for a proper mvc structure. reqd for automation post-1.2.
+ // in the mean time this duplicates much of
+ // MIDIInstrumentParameterPanel::slotControllerChanged etc
+
+ switch (controller) {
+
+ case MIDI_CONTROLLER_VOLUME:
+ RG_DEBUG << "Setting volume for instrument " << instrument->getId() << " to " << value << endl;
+ instrument->setVolume(value);
+ break;
+
+ case MIDI_CONTROLLER_PAN:
+ RG_DEBUG << "Setting pan for instrument " << instrument->getId() << " to " << value << endl;
+ instrument->setPan(value);
+ break;
+
+ default: {
+ ControlList cl = md->getIPBControlParameters();
+ for (ControlList::const_iterator i = cl.begin();
+ i != cl.end(); ++i) {
+ if ((*i).getControllerValue() == controller) {
+ RG_DEBUG << "Setting controller " << controller << " for instrument " << instrument->getId() << " to " << value << endl;
+ instrument->setControllerValue(controller, value);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case Instrument::SoftSynth:
+ case Instrument::Audio:
+
+ switch (controller) {
+
+ case MIDI_CONTROLLER_VOLUME:
+ RG_DEBUG << "Setting volume for instrument " << instrument->getId() << " to " << value << endl;
+ instrument->setLevel(AudioLevel::fader_to_dB
+ (value, 127, AudioLevel::ShortFader));
+ break;
+
+ case MIDI_CONTROLLER_PAN:
+ RG_DEBUG << "Setting pan for instrument " << instrument->getId() << " to " << value << endl;
+ instrument->setPan(MidiByte((value / 64.0) * 100.0 + 0.01));
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ emit instrumentParametersChanged(instrument->getId());
+
+ //!!! send out updates via MIDI
+}
+
+void
+RosegardenGUIView::initChordNameRuler()
+{
+ getTrackEditor()->getChordNameRuler()->setReady();
+}
+
+EventView *
+RosegardenGUIView::createEventView(std::vector<Segment *> segmentsToEdit)
+{
+ EventView *eventView = new EventView(getDocument(),
+ segmentsToEdit,
+ this);
+
+ connect(eventView, SIGNAL(windowActivated()),
+ this, SLOT(slotActiveMainWindowChanged()));
+
+ connect(eventView, SIGNAL(selectTrack(int)),
+ this, SLOT(slotSelectTrackSegments(int)));
+
+ connect(eventView, SIGNAL(saveFile()),
+ RosegardenGUIApp::self(), SLOT(slotFileSave()));
+
+ connect(eventView, SIGNAL(openInNotation(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsNotation(std::vector<Segment *>)));
+ connect(eventView, SIGNAL(openInMatrix(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsMatrix(std::vector<Segment *>)));
+ connect(eventView, SIGNAL(openInPercussionMatrix(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsPercussionMatrix(std::vector<Segment *>)));
+ connect(eventView, SIGNAL(openInEventList(std::vector<Segment *>)),
+ this, SLOT(slotEditSegmentsEventList(std::vector<Segment *>)));
+ connect(eventView, SIGNAL(editTriggerSegment(int)),
+ this, SLOT(slotEditTriggerSegment(int)));
+ connect(this, SIGNAL(compositionStateUpdate()),
+ eventView, SLOT(slotCompositionStateUpdate()));
+ connect(RosegardenGUIApp::self(), SIGNAL(compositionStateUpdate()),
+ eventView, SLOT(slotCompositionStateUpdate()));
+ connect(eventView, SIGNAL(toggleSolo(bool)),
+ RosegardenGUIApp::self(), SLOT(slotToggleSolo(bool)));
+
+ // create keyboard accelerators on view
+ //
+ RosegardenGUIApp *par = dynamic_cast<RosegardenGUIApp*>(parent());
+
+ if (par) {
+ par->plugAccelerators(eventView, eventView->getAccelerators());
+ }
+
+ return eventView;
+}
+
+}
+#include "RosegardenGUIView.moc"