diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
commit | 145364a8af6a1fec06556221e66d4b724a62fc9a (patch) | |
tree | 53bd71a544008c518034f208d64c932dc2883f50 /src/gui/application/RosegardenGUIView.cpp | |
download | rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.tar.gz rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.zip |
Added old abandoned KDE3 version of the RoseGarden MIDI tool
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/rosegarden@1097595 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/gui/application/RosegardenGUIView.cpp')
-rw-r--r-- | src/gui/application/RosegardenGUIView.cpp | 2041 |
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" |