You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2042 lines
68 KiB
2042 lines
68 KiB
/* -*- 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 <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <richard.bown@ferventsoftware.com>
|
|
|
|
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 <tqapplication.h>
|
|
#include <tqcursor.h>
|
|
#include <tqdialog.h>
|
|
#include <tqfileinfo.h>
|
|
#include <tqobject.h>
|
|
#include <tqstring.h>
|
|
#include <tqvbox.h>
|
|
#include <tqwidget.h>
|
|
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
// Use this to define the basic unit of the main TQCanvas 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 TQWidget *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,
|
|
TQWidget *parent,
|
|
const char* /*name*/)
|
|
: TQVBox(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(),
|
|
TQT_SIGNAL(editSegment(Segment*)),
|
|
TQT_SLOT(slotEditSegment(Segment*)));
|
|
|
|
connect(m_trackEditor->getSegmentCanvas(),
|
|
TQT_SIGNAL(editSegmentNotation(Segment*)),
|
|
TQT_SLOT(slotEditSegmentNotation(Segment*)));
|
|
|
|
connect(m_trackEditor->getSegmentCanvas(),
|
|
TQT_SIGNAL(editSegmentMatrix(Segment*)),
|
|
TQT_SLOT(slotEditSegmentMatrix(Segment*)));
|
|
|
|
connect(m_trackEditor->getSegmentCanvas(),
|
|
TQT_SIGNAL(editSegmentAudio(Segment*)),
|
|
TQT_SLOT(slotEditSegmentAudio(Segment*)));
|
|
|
|
connect(m_trackEditor->getSegmentCanvas(),
|
|
TQT_SIGNAL(audioSegmentAutoSplit(Segment*)),
|
|
TQT_SLOT(slotSegmentAutoSplit(Segment*)));
|
|
|
|
connect(m_trackEditor->getSegmentCanvas(),
|
|
TQT_SIGNAL(editSegmentEventList(Segment*)),
|
|
TQT_SLOT(slotEditSegmentEventList(Segment*)));
|
|
|
|
connect(m_trackEditor->getSegmentCanvas(),
|
|
TQT_SIGNAL(editRepeat(Segment*, timeT)),
|
|
TQT_SLOT(slotEditRepeat(Segment*, timeT)));
|
|
|
|
connect(m_trackEditor->getSegmentCanvas(),
|
|
TQT_SIGNAL(setPointerPosition(timeT)),
|
|
doc, TQT_SLOT(slotSetPointerPosition(timeT)));
|
|
|
|
connect(m_trackEditor,
|
|
TQT_SIGNAL(droppedDocument(TQString)),
|
|
parent,
|
|
TQT_SLOT(slotOpenDroppedURL(TQString)));
|
|
|
|
connect(m_trackEditor,
|
|
TQT_SIGNAL(droppedAudio(TQString)),
|
|
this,
|
|
TQT_SLOT(slotDroppedAudio(TQString)));
|
|
|
|
connect(m_trackEditor,
|
|
TQT_SIGNAL(droppedNewAudio(TQString)),
|
|
this,
|
|
TQT_SLOT(slotDroppedNewAudio(TQString)));
|
|
|
|
connect(m_instrumentParameterBox,
|
|
TQT_SIGNAL(changeInstrumentLabel(InstrumentId, TQString)),
|
|
this,
|
|
TQT_SLOT(slotChangeInstrumentLabel(InstrumentId, TQString)));
|
|
|
|
connect(m_instrumentParameterBox,
|
|
TQT_SIGNAL(changeInstrumentLabel(InstrumentId, TQString)),
|
|
m_trackParameterBox,
|
|
TQT_SLOT(slotInstrumentLabelChanged(InstrumentId, TQString)));
|
|
|
|
connect(m_trackEditor->getTrackButtons(),
|
|
TQT_SIGNAL(nameChanged()),
|
|
m_trackParameterBox,
|
|
TQT_SLOT(slotSelectedTrackNameChanged()));
|
|
|
|
connect(m_trackEditor->getTrackButtons(),
|
|
TQT_SIGNAL(instrumentSelected(int)),
|
|
m_trackParameterBox,
|
|
TQT_SLOT(slotUpdateControls(int)));
|
|
|
|
connect(m_trackParameterBox,
|
|
TQT_SIGNAL(instrumentSelected(TrackId, int)),
|
|
m_trackEditor->getTrackButtons(),
|
|
TQT_SLOT(slotTrackInstrumentSelection(TrackId, int)));
|
|
|
|
connect(this, TQT_SIGNAL(controllerDeviceEventReceived(MappedEvent *, const void *)),
|
|
this, TQT_SLOT(slotControllerDeviceEventReceived(MappedEvent *, const void *)));
|
|
|
|
if (doc) {
|
|
/* signal no longer exists
|
|
connect(doc, TQT_SIGNAL(recordingSegmentUpdated(Segment *,
|
|
timeT)),
|
|
this, TQT_SLOT(slotUpdateRecordingSegment(Segment *,
|
|
timeT)));
|
|
*/
|
|
|
|
TQObject::connect
|
|
(getCommandHistory(), TQT_SIGNAL(commandExecuted()),
|
|
m_trackEditor->getSegmentCanvas(), TQT_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 TQString 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(TQString name)
|
|
{
|
|
const TQWidget *ww = dynamic_cast<const TQWidget *>(sender());
|
|
TQWidget *w = const_cast<TQWidget *>(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, TQT_SIGNAL(changeTempo(timeT,
|
|
tempoT,
|
|
tempoT,
|
|
TempoDialog::TempoDialogAction)),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotChangeTempo(timeT,
|
|
tempoT,
|
|
tempoT,
|
|
TempoDialog::TempoDialogAction)));
|
|
|
|
|
|
connect(notationView, TQT_SIGNAL(windowActivated()),
|
|
this, TQT_SLOT(slotActiveMainWindowChanged()));
|
|
|
|
connect(notationView, TQT_SIGNAL(selectTrack(int)),
|
|
this, TQT_SLOT(slotSelectTrackSegments(int)));
|
|
|
|
connect(notationView, TQT_SIGNAL(play()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotPlay()));
|
|
connect(notationView, TQT_SIGNAL(stop()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotStop()));
|
|
connect(notationView, TQT_SIGNAL(fastForwardPlayback()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotFastforward()));
|
|
connect(notationView, TQT_SIGNAL(rewindPlayback()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotRewind()));
|
|
connect(notationView, TQT_SIGNAL(fastForwardPlaybackToEnd()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotFastForwardToEnd()));
|
|
connect(notationView, TQT_SIGNAL(rewindPlaybackToBeginning()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotRewindToBeginning()));
|
|
connect(notationView, TQT_SIGNAL(panic()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotPanic()));
|
|
|
|
connect(notationView, TQT_SIGNAL(saveFile()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotFileSave()));
|
|
connect(notationView, TQT_SIGNAL(jumpPlaybackTo(timeT)),
|
|
getDocument(), TQT_SLOT(slotSetPointerPosition(timeT)));
|
|
connect(notationView, TQT_SIGNAL(openInNotation(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsNotation(std::vector<Segment *>)));
|
|
connect(notationView, TQT_SIGNAL(openInMatrix(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsMatrix(std::vector<Segment *>)));
|
|
connect(notationView, TQT_SIGNAL(openInPercussionMatrix(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsPercussionMatrix(std::vector<Segment *>)));
|
|
connect(notationView, TQT_SIGNAL(openInEventList(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsEventList(std::vector<Segment *>)));
|
|
/* hjj: WHAT DO DO WITH THIS ?
|
|
connect(notationView, TQT_SIGNAL(editMetadata(TQString)),
|
|
this, TQT_SLOT(slotEditMetadata(TQString)));
|
|
*/
|
|
connect(notationView, TQT_SIGNAL(editTriggerSegment(int)),
|
|
this, TQT_SLOT(slotEditTriggerSegment(int)));
|
|
connect(notationView, TQT_SIGNAL(staffLabelChanged(TrackId, TQString)),
|
|
this, TQT_SLOT(slotChangeTrackLabel(TrackId, TQString)));
|
|
connect(notationView, TQT_SIGNAL(toggleSolo(bool)),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotToggleSolo(bool)));
|
|
connect(notationView, TQT_SIGNAL(editTimeSignature(timeT)),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotEditTempos(timeT)));
|
|
|
|
SequenceManager *sM = getDocument()->getSequenceManager();
|
|
|
|
connect(sM, TQT_SIGNAL(insertableNoteOnReceived(int, int)),
|
|
notationView, TQT_SLOT(slotInsertableNoteOnReceived(int, int)));
|
|
connect(sM, TQT_SIGNAL(insertableNoteOffReceived(int, int)),
|
|
notationView, TQT_SLOT(slotInsertableNoteOffReceived(int, int)));
|
|
|
|
connect(notationView, TQT_SIGNAL(stepByStepTargetRequested(TQObject *)),
|
|
this, TQT_SIGNAL(stepByStepTargetRequested(TQObject *)));
|
|
connect(this, TQT_SIGNAL(stepByStepTargetRequested(TQObject *)),
|
|
notationView, TQT_SLOT(slotStepByStepTargetRequested(TQObject *)));
|
|
connect(RosegardenGUIApp::self(), TQT_SIGNAL(compositionStateUpdate()),
|
|
notationView, TQT_SLOT(slotCompositionStateUpdate()));
|
|
connect(this, TQT_SIGNAL(compositionStateUpdate()),
|
|
notationView, TQT_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, TQT_SIGNAL(changeTempo(timeT,
|
|
tempoT,
|
|
tempoT,
|
|
TempoDialog::TempoDialogAction)),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotChangeTempo(timeT,
|
|
tempoT,
|
|
tempoT,
|
|
TempoDialog::TempoDialogAction)));
|
|
|
|
connect(matrixView, TQT_SIGNAL(windowActivated()),
|
|
this, TQT_SLOT(slotActiveMainWindowChanged()));
|
|
|
|
connect(matrixView, TQT_SIGNAL(selectTrack(int)),
|
|
this, TQT_SLOT(slotSelectTrackSegments(int)));
|
|
|
|
connect(matrixView, TQT_SIGNAL(play()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotPlay()));
|
|
connect(matrixView, TQT_SIGNAL(stop()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotStop()));
|
|
connect(matrixView, TQT_SIGNAL(fastForwardPlayback()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotFastforward()));
|
|
connect(matrixView, TQT_SIGNAL(rewindPlayback()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotRewind()));
|
|
connect(matrixView, TQT_SIGNAL(fastForwardPlaybackToEnd()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotFastForwardToEnd()));
|
|
connect(matrixView, TQT_SIGNAL(rewindPlaybackToBeginning()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotRewindToBeginning()));
|
|
connect(matrixView, TQT_SIGNAL(panic()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotPanic()));
|
|
|
|
connect(matrixView, TQT_SIGNAL(saveFile()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotFileSave()));
|
|
connect(matrixView, TQT_SIGNAL(jumpPlaybackTo(timeT)),
|
|
getDocument(), TQT_SLOT(slotSetPointerPosition(timeT)));
|
|
connect(matrixView, TQT_SIGNAL(openInNotation(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsNotation(std::vector<Segment *>)));
|
|
connect(matrixView, TQT_SIGNAL(openInMatrix(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsMatrix(std::vector<Segment *>)));
|
|
connect(matrixView, TQT_SIGNAL(openInEventList(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsEventList(std::vector<Segment *>)));
|
|
connect(matrixView, TQT_SIGNAL(editTriggerSegment(int)),
|
|
this, TQT_SLOT(slotEditTriggerSegment(int)));
|
|
connect(matrixView, TQT_SIGNAL(toggleSolo(bool)),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotToggleSolo(bool)));
|
|
connect(matrixView, TQT_SIGNAL(editTimeSignature(timeT)),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotEditTempos(timeT)));
|
|
|
|
SequenceManager *sM = getDocument()->getSequenceManager();
|
|
|
|
connect(sM, TQT_SIGNAL(insertableNoteOnReceived(int, int)),
|
|
matrixView, TQT_SLOT(slotInsertableNoteOnReceived(int, int)));
|
|
connect(sM, TQT_SIGNAL(insertableNoteOffReceived(int, int)),
|
|
matrixView, TQT_SLOT(slotInsertableNoteOffReceived(int, int)));
|
|
|
|
connect(matrixView, TQT_SIGNAL(stepByStepTargetRequested(TQObject *)),
|
|
this, TQT_SIGNAL(stepByStepTargetRequested(TQObject *)));
|
|
connect(this, TQT_SIGNAL(stepByStepTargetRequested(TQObject *)),
|
|
matrixView, TQT_SLOT(slotStepByStepTargetRequested(TQObject *)));
|
|
connect(RosegardenGUIApp::self(), TQT_SIGNAL(compositionStateUpdate()),
|
|
matrixView, TQT_SLOT(slotCompositionStateUpdate()));
|
|
connect(this, TQT_SIGNAL(compositionStateUpdate()),
|
|
matrixView, TQT_SLOT(slotCompositionStateUpdate()));
|
|
connect(this,
|
|
TQT_SIGNAL(instrumentLevelsChanged(InstrumentId,
|
|
const LevelInfo &)),
|
|
matrixView,
|
|
TQT_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() == TQDialog::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);
|
|
|
|
TQString application = config->readEntry("externalaudioeditor", "");
|
|
|
|
if (application == "") {
|
|
application = AudioConfigurationPage::getBestAvailableAudioEditor();
|
|
}
|
|
|
|
TQStringList splitCommand = TQStringList::split(" ", application);
|
|
|
|
if (splitCommand.size() == 0) {
|
|
|
|
std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
|
|
<< "external editor \"" << application.ascii()
|
|
<< "\" 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 ;
|
|
}
|
|
|
|
TQFileInfo *appInfo = new TQFileInfo(splitCommand[0]);
|
|
if (appInfo->exists() == false || appInfo->isExecutable() == false) {
|
|
std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
|
|
<< "can't execute \"" << splitCommand[0].ascii() << "\""
|
|
<< 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
|
|
TQApplication::setOverrideCursor(TQCursor(TQt::waitCursor));
|
|
|
|
// Prepare the process
|
|
//
|
|
KProcess *process = new KProcess();
|
|
(*process) << splitCommand;
|
|
(*process) << TQString(aF->getFilename().c_str());
|
|
|
|
// Start it
|
|
//
|
|
if (!process->start()) {
|
|
std::cerr << "RosegardenGUIView::slotEditSegmentAudio() - "
|
|
<< "can't start external editor" << std::endl;
|
|
}
|
|
|
|
// restore cursor
|
|
TQApplication::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,
|
|
TQString label)
|
|
{
|
|
m_trackEditor->getTrackButtons()->changeInstrumentLabel(id, label);
|
|
}
|
|
|
|
void
|
|
RosegardenGUIView::slotChangeTrackLabel(TrackId id,
|
|
TQString 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(TQString audioDesc)
|
|
{
|
|
TQTextIStream s(&audioDesc);
|
|
|
|
TQString url;
|
|
int trackId;
|
|
timeT time;
|
|
url = s.readLine();
|
|
s >> trackId;
|
|
s >> time;
|
|
|
|
std::cerr << "RosegardenGUIView::slotDroppedNewAudio: url " << url.ascii() << ", 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, TQT_SIGNAL(setProgress(int)),
|
|
progressDlg.progressBar(), TQT_SLOT(setValue(int)));
|
|
connect(&aFM, TQT_SIGNAL(setOperationName(TQString)),
|
|
&progressDlg, TQT_SLOT(slotSetOperationName(TQString)));
|
|
connect(&progressDlg, TQT_SIGNAL(cancelClicked()),
|
|
&aFM, TQT_SLOT(slotStopImport()));
|
|
|
|
try {
|
|
audioFileId = aFM.importURL(kurl, sampleRate);
|
|
} catch (AudioFileManager::BadAudioPathException e) {
|
|
CurrentProgressDialog::freeze();
|
|
TQString errorString = i18n("Can't add dropped file. ") + strtoqstr(e.getMessage());
|
|
KMessageBox::sorry(this, errorString);
|
|
return ;
|
|
} catch (SoundFile::BadSoundFileException e) {
|
|
CurrentProgressDialog::freeze();
|
|
TQString errorString = i18n("Can't add dropped file. ") + strtoqstr(e.getMessage());
|
|
KMessageBox::sorry(this, errorString);
|
|
return ;
|
|
}
|
|
|
|
disconnect(&progressDlg, TQT_SIGNAL(cancelClicked()),
|
|
&aFM, TQT_SLOT(slotStopImport()));
|
|
connect(&progressDlg, TQT_SIGNAL(cancelClicked()),
|
|
&aFM, TQT_SLOT(slotStopPreview()));
|
|
progressDlg.progressBar()->show();
|
|
progressDlg.slotSetOperationName(i18n("Generating audio preview..."));
|
|
|
|
try {
|
|
aFM.generatePreview(audioFileId);
|
|
} catch (Exception e) {
|
|
CurrentProgressDialog::freeze();
|
|
TQString 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, TQT_SIGNAL(cancelClicked()),
|
|
&aFM, TQT_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(TQString audioDesc)
|
|
{
|
|
TQTextIStream 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
|
|
TQObject::connect
|
|
(getDocument(), TQT_SIGNAL(recordingSegmentUpdated(Segment *, timeT)),
|
|
view, TQT_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 TQWidget *w)
|
|
{
|
|
m_lastActiveMainWindow = w;
|
|
}
|
|
|
|
void
|
|
RosegardenGUIView::slotActiveMainWindowChanged()
|
|
{
|
|
const TQWidget *w = dynamic_cast<const TQWidget *>(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, TQT_SIGNAL(windowActivated()),
|
|
this, TQT_SLOT(slotActiveMainWindowChanged()));
|
|
|
|
connect(eventView, TQT_SIGNAL(selectTrack(int)),
|
|
this, TQT_SLOT(slotSelectTrackSegments(int)));
|
|
|
|
connect(eventView, TQT_SIGNAL(saveFile()),
|
|
RosegardenGUIApp::self(), TQT_SLOT(slotFileSave()));
|
|
|
|
connect(eventView, TQT_SIGNAL(openInNotation(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsNotation(std::vector<Segment *>)));
|
|
connect(eventView, TQT_SIGNAL(openInMatrix(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsMatrix(std::vector<Segment *>)));
|
|
connect(eventView, TQT_SIGNAL(openInPercussionMatrix(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsPercussionMatrix(std::vector<Segment *>)));
|
|
connect(eventView, TQT_SIGNAL(openInEventList(std::vector<Segment *>)),
|
|
this, TQT_SLOT(slotEditSegmentsEventList(std::vector<Segment *>)));
|
|
connect(eventView, TQT_SIGNAL(editTriggerSegment(int)),
|
|
this, TQT_SLOT(slotEditTriggerSegment(int)));
|
|
connect(this, TQT_SIGNAL(compositionStateUpdate()),
|
|
eventView, TQT_SLOT(slotCompositionStateUpdate()));
|
|
connect(RosegardenGUIApp::self(), TQT_SIGNAL(compositionStateUpdate()),
|
|
eventView, TQT_SLOT(slotCompositionStateUpdate()));
|
|
connect(eventView, TQT_SIGNAL(toggleSolo(bool)),
|
|
RosegardenGUIApp::self(), TQT_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"
|