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.
1163 lines
32 KiB
1163 lines
32 KiB
/*
|
|
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 "TransportDialog.h"
|
|
|
|
#include <tdelocale.h>
|
|
#include <kstddirs.h>
|
|
#include "base/Composition.h"
|
|
#include "base/NotationTypes.h"
|
|
#include "base/RealTime.h"
|
|
#include "misc/Debug.h"
|
|
#include "gui/application/RosegardenApplication.h"
|
|
#include "gui/general/MidiPitchLabel.h"
|
|
#include "gui/studio/StudioControl.h"
|
|
#include "gui/widgets/Label.h"
|
|
#include "sound/MappedEvent.h"
|
|
#include "document/ConfigGroups.h"
|
|
#include <tdeconfig.h>
|
|
#include <tdeglobal.h>
|
|
#include <tqaccel.h>
|
|
#include <tqcolor.h>
|
|
#include <tqcstring.h>
|
|
#include <tqdatastream.h>
|
|
#include <tqfont.h>
|
|
#include <tqhbox.h>
|
|
#include <tqlabel.h>
|
|
#include <tqpalette.h>
|
|
#include <tqpixmap.h>
|
|
#include <tqpushbutton.h>
|
|
#include <tqstring.h>
|
|
#include <tqtimer.h>
|
|
#include <tqwidget.h>
|
|
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
TransportDialog::TransportDialog(TQWidget *parent,
|
|
const char *name,
|
|
WFlags flags):
|
|
TQWidget(parent, name, WType_TopLevel | WStyle_DialogBorder | WStyle_Minimize | WStyle_SysMenu | WDestructiveClose),
|
|
m_transport(0),
|
|
m_lastTenHours(0),
|
|
m_lastUnitHours(0),
|
|
m_lastTenMinutes(0),
|
|
m_lastUnitMinutes(0),
|
|
m_lastTenSeconds(0),
|
|
m_lastUnitSeconds(0),
|
|
m_lastTenths(0),
|
|
m_lastHundreths(0),
|
|
m_lastThousandths(0),
|
|
m_lastTenThousandths(0),
|
|
m_lastNegative(false),
|
|
m_lastMode(RealMode),
|
|
m_currentMode(RealMode),
|
|
m_tempo(0),
|
|
m_numerator(0),
|
|
m_denominator(0),
|
|
m_framesPerSecond(24),
|
|
m_bitsPerFrame(80),
|
|
m_isExpanded(true),
|
|
m_haveOriginalBackground(false),
|
|
m_isBackgroundSet(false),
|
|
m_sampleRate(0)
|
|
{
|
|
m_transport = new RosegardenTransport(this);
|
|
|
|
setCaption(i18n("Rosegarden Transport"));
|
|
|
|
resetFonts();
|
|
|
|
initModeMap();
|
|
|
|
// set the LCD frame background to black
|
|
//
|
|
m_transport->LCDBoxFrame->setBackgroundColor(TQt::black);
|
|
|
|
// set all the pixmap backgrounds to black to avoid
|
|
// flickering when we update
|
|
//
|
|
m_transport->TenThousandthsPixmap->setBackgroundColor(TQt::black);
|
|
m_transport->ThousandthsPixmap->setBackgroundColor(TQt::black);
|
|
m_transport->HundredthsPixmap->setBackgroundColor(TQt::black);
|
|
m_transport->TenthsPixmap->setBackgroundColor(TQt::black);
|
|
m_transport->UnitSecondsPixmap->setBackgroundColor(TQt::black);
|
|
m_transport->TenSecondsPixmap->setBackgroundColor(TQt::black);
|
|
m_transport->UnitMinutesPixmap->setBackgroundColor(TQt::black);
|
|
m_transport->TenMinutesPixmap->setBackgroundColor(TQt::black);
|
|
m_transport->UnitHoursPixmap->setBackgroundColor(TQt::black);
|
|
m_transport->TenHoursPixmap->setBackgroundColor(TQt::black);
|
|
m_transport->NegativePixmap->setBackgroundColor(TQt::black);
|
|
|
|
// unset the negative sign to begin with
|
|
m_transport->NegativePixmap->clear();
|
|
|
|
// Set our toggle buttons
|
|
//
|
|
m_transport->PlayButton->setToggleButton(true);
|
|
m_transport->RecordButton->setToggleButton(true);
|
|
|
|
// Disable the loop button if JACK transport enabled, because this
|
|
// causes a nasty race condition, and it just seems our loops are not JACK compatible
|
|
// #1240039 - DMM
|
|
// TDEConfig* config = rgapp->config();
|
|
// config->setGroup(SequencerOptionsConfigGroup);
|
|
// if (config->readBoolEntry("jacktransport", false))
|
|
// {
|
|
// m_transport->LoopButton->setEnabled(false);
|
|
// }
|
|
|
|
// fix and hold the size of the dialog
|
|
//
|
|
setMinimumSize(m_transport->width(), m_transport->height());
|
|
setMaximumSize(m_transport->width(), m_transport->height());
|
|
|
|
loadPixmaps();
|
|
|
|
// Create Midi label timers
|
|
m_midiInTimer = new TQTimer(this);
|
|
m_midiOutTimer = new TQTimer(this);
|
|
m_clearMetronomeTimer = new TQTimer(this);
|
|
|
|
connect(m_midiInTimer, TQ_SIGNAL(timeout()),
|
|
TQ_SLOT(slotClearMidiInLabel()));
|
|
|
|
connect(m_midiOutTimer, TQ_SIGNAL(timeout()),
|
|
TQ_SLOT(slotClearMidiOutLabel()));
|
|
|
|
connect(m_clearMetronomeTimer, TQ_SIGNAL(timeout()),
|
|
TQ_SLOT(slotResetBackground()));
|
|
|
|
m_transport->TimeDisplayLabel->hide();
|
|
m_transport->ToEndLabel->hide();
|
|
|
|
connect(m_transport->TimeDisplayButton, TQ_SIGNAL(clicked()),
|
|
TQ_SLOT(slotChangeTimeDisplay()));
|
|
|
|
connect(m_transport->ToEndButton, TQ_SIGNAL(clicked()),
|
|
TQ_SLOT(slotChangeToEnd()));
|
|
|
|
connect(m_transport->LoopButton, TQ_SIGNAL(clicked()),
|
|
TQ_SLOT(slotLoopButtonClicked()));
|
|
|
|
connect(m_transport->PanelOpenButton, TQ_SIGNAL(clicked()),
|
|
TQ_SLOT(slotPanelOpenButtonClicked()));
|
|
|
|
connect(m_transport->PanelCloseButton, TQ_SIGNAL(clicked()),
|
|
TQ_SLOT(slotPanelCloseButtonClicked()));
|
|
|
|
connect(m_transport->PanicButton, TQ_SIGNAL(clicked()), TQ_SIGNAL(panic()));
|
|
|
|
m_panelOpen = *m_transport->PanelOpenButton->pixmap();
|
|
m_panelClosed = *m_transport->PanelCloseButton->pixmap();
|
|
|
|
|
|
connect(m_transport->SetStartLPButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotSetStartLoopingPointAtMarkerPos()));
|
|
connect(m_transport->SetStopLPButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotSetStopLoopingPointAtMarkerPos()));
|
|
|
|
// clear labels
|
|
//
|
|
slotClearMidiInLabel();
|
|
slotClearMidiOutLabel();
|
|
|
|
// and by default we close the lower panel
|
|
//
|
|
int rfh = m_transport->RecordingFrame->height();
|
|
m_transport->RecordingFrame->hide();
|
|
setFixedSize(width(), height() - rfh);
|
|
m_transport->PanelOpenButton->setPixmap(m_panelClosed);
|
|
|
|
// and since by default we show real time (not SMPTE), by default
|
|
// we hide the small colon pixmaps
|
|
//
|
|
m_transport->SecondColonPixmap->hide();
|
|
m_transport->HundredthColonPixmap->hide();
|
|
|
|
// We have to specify these settings in this class (copied
|
|
// from rosegardentransport.cpp) as we're using a specialised
|
|
// widgets for TempoDisplay. Ugly but works - does mean that
|
|
// if the rest of the Transport ever changes then this code
|
|
// will have to as well.
|
|
//
|
|
TQPalette pal;
|
|
pal.setColor(TQColorGroup::Foreground, TQColor(192, 216, 255));
|
|
|
|
m_transport->TempoDisplay->setPalette(pal);
|
|
m_transport->TempoDisplay->setAlignment(int(TQLabel::AlignVCenter | TQLabel::AlignRight));
|
|
|
|
m_transport->TimeSigDisplay->setPalette(pal);
|
|
m_transport->TimeSigDisplay->setAlignment(int(TQLabel::AlignVCenter | TQLabel::AlignRight));
|
|
|
|
TQFont localFont(m_transport->OutDisplay->font() );
|
|
localFont.setFamily( "lucida" );
|
|
localFont.setBold( TRUE );
|
|
|
|
m_transport->TempoDisplay->setFont( localFont );
|
|
m_transport->TimeSigDisplay->setFont( localFont );
|
|
|
|
connect(m_transport->TempoDisplay, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTempo()));
|
|
|
|
connect(m_transport->TempoDisplay, TQ_SIGNAL(scrollWheel(int)),
|
|
this, TQ_SIGNAL(scrollTempo(int)));
|
|
|
|
connect(m_transport->TimeSigDisplay, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTimeSignature()));
|
|
|
|
// toil through the individual pixmaps
|
|
connect(m_transport->NegativePixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->TenHoursPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->UnitHoursPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->HourColonPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->TenMinutesPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->UnitMinutesPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->MinuteColonPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->TenSecondsPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->UnitSecondsPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->SecondColonPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->TenthsPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->HundredthsPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->HundredthColonPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->TenThousandthsPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
connect(m_transport->ThousandthsPixmap, TQ_SIGNAL(doubleClicked()),
|
|
this, TQ_SLOT(slotEditTime()));
|
|
|
|
// accelerator object
|
|
//
|
|
m_accelerators = new TQAccel(this);
|
|
}
|
|
|
|
TransportDialog::~TransportDialog()
|
|
{
|
|
if (isVisible()) {
|
|
TDEConfig* config = rgapp->config();
|
|
config->setGroup(GeneralOptionsConfigGroup);
|
|
config->writeEntry("transportx", x());
|
|
config->writeEntry("transporty", y());
|
|
}
|
|
}
|
|
|
|
std::string
|
|
TransportDialog::getCurrentModeAsString()
|
|
{
|
|
bool found = false;
|
|
for (std::map<std::string, TimeDisplayMode>::iterator iter = m_modeMap.begin();
|
|
iter != m_modeMap.end() && !found;
|
|
iter++)
|
|
{
|
|
if (iter->second == m_currentMode) {
|
|
return iter->first;
|
|
}
|
|
}
|
|
|
|
// we shouldn't get here unless the map is not well-configured
|
|
RG_DEBUG << "TransportDialog::getCurrentModeAsString: could not map current mode "
|
|
<< m_currentMode << " to string." << endl;
|
|
throw Exception("could not map current mode to string.");
|
|
}
|
|
|
|
void
|
|
TransportDialog::initModeMap()
|
|
{
|
|
m_modeMap["RealMode"] = RealMode;
|
|
m_modeMap["SMPTEMode"] = SMPTEMode;
|
|
m_modeMap["BarMode"] = BarMode;
|
|
m_modeMap["BarMetronomeMode"] = BarMetronomeMode;
|
|
m_modeMap["FrameMode"] = FrameMode;
|
|
}
|
|
|
|
void
|
|
TransportDialog::show()
|
|
{
|
|
TDEConfig* config = rgapp->config();
|
|
config->setGroup(GeneralOptionsConfigGroup);
|
|
int x = config->readNumEntry("transportx", -1);
|
|
int y = config->readNumEntry("transporty", -1);
|
|
if (x >= 0 && y >= 0) {
|
|
int dw = TQApplication::desktop()->availableGeometry(TQPoint(x, y)).width();
|
|
int dh = TQApplication::desktop()->availableGeometry(TQPoint(x, y)).height();
|
|
if (x + m_transport->width() > dw) x = dw - m_transport->width();
|
|
if (y + m_transport->height() > dh) y = dh - m_transport->height();
|
|
move(x, y);
|
|
// std::cerr << "TransportDialog::show(): moved to " << x << "," << y << std::endl;
|
|
TQWidget::show();
|
|
// std::cerr << "TransportDialog::show(): now at " << this->x() << "," << this->y() << std::endl;
|
|
} else {
|
|
TQWidget::show();
|
|
}
|
|
}
|
|
|
|
void
|
|
TransportDialog::hide()
|
|
{
|
|
if (isVisible()) {
|
|
TDEConfig* config = rgapp->config();
|
|
config->setGroup(GeneralOptionsConfigGroup);
|
|
config->writeEntry("transportx", x());
|
|
config->writeEntry("transporty", y());
|
|
}
|
|
TQWidget::hide();
|
|
}
|
|
|
|
void
|
|
TransportDialog::loadPixmaps()
|
|
{
|
|
m_lcdList.clear();
|
|
TQString fileName;
|
|
TQString pixmapDir = TDEGlobal::dirs()->findResource("appdata", "pixmaps/");
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
fileName = TQString("%1/transport/led-%2.xpm").arg(pixmapDir).arg(i);
|
|
if (!m_lcdList[i].load(fileName)) {
|
|
std::cerr << "TransportDialog - failed to load pixmap \""
|
|
<< fileName.ascii() << "\"" << std::endl;
|
|
}
|
|
}
|
|
|
|
// Load the "negative" sign pixmap
|
|
//
|
|
fileName = TQString("%1/transport/led--.xpm").arg(pixmapDir);
|
|
m_lcdNegative.load(fileName);
|
|
|
|
}
|
|
|
|
void
|
|
TransportDialog::resetFonts()
|
|
{
|
|
resetFont(m_transport->TimeSigLabel);
|
|
resetFont(m_transport->TimeSigDisplay);
|
|
resetFont(m_transport->TempoLabel);
|
|
resetFont(m_transport->TempoDisplay);
|
|
resetFont(m_transport->DivisionLabel);
|
|
resetFont(m_transport->DivisionDisplay);
|
|
resetFont(m_transport->InLabel);
|
|
resetFont(m_transport->InDisplay);
|
|
resetFont(m_transport->OutLabel);
|
|
resetFont(m_transport->OutDisplay);
|
|
resetFont(m_transport->ToEndLabel);
|
|
resetFont(m_transport->TimeDisplayLabel);
|
|
}
|
|
|
|
void
|
|
TransportDialog::resetFont(TQWidget *w)
|
|
{
|
|
TQFont font = w->font();
|
|
font.setPixelSize(10);
|
|
w->setFont(font);
|
|
}
|
|
|
|
void
|
|
TransportDialog::setSMPTEResolution(int framesPerSecond,
|
|
int bitsPerFrame)
|
|
{
|
|
m_framesPerSecond = framesPerSecond;
|
|
m_bitsPerFrame = bitsPerFrame;
|
|
}
|
|
|
|
void
|
|
TransportDialog::getSMPTEResolution(int &framesPerSecond,
|
|
int &bitsPerFrame)
|
|
{
|
|
framesPerSecond = m_framesPerSecond;
|
|
bitsPerFrame = m_bitsPerFrame;
|
|
}
|
|
|
|
void
|
|
TransportDialog::computeSampleRate()
|
|
{
|
|
if (m_sampleRate == 0) {
|
|
|
|
TQCString replyType;
|
|
TQByteArray replyData;
|
|
m_sampleRate = 0;
|
|
|
|
if (rgapp->sequencerCall("getSampleRate()", replyType, replyData)) {
|
|
TQDataStream streamIn(replyData, IO_ReadOnly);
|
|
unsigned int result;
|
|
streamIn >> result;
|
|
m_sampleRate = result;
|
|
} else {
|
|
m_sampleRate = -1;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
TransportDialog::cycleThroughModes()
|
|
{
|
|
switch (m_currentMode) {
|
|
|
|
case RealMode:
|
|
if (m_sampleRate > 0)
|
|
m_currentMode = FrameMode;
|
|
else
|
|
m_currentMode = BarMode;
|
|
break;
|
|
|
|
case FrameMode:
|
|
m_currentMode = BarMode;
|
|
break;
|
|
|
|
case SMPTEMode:
|
|
m_currentMode = BarMode;
|
|
break;
|
|
|
|
case BarMode:
|
|
m_currentMode = BarMetronomeMode;
|
|
break;
|
|
|
|
case BarMetronomeMode:
|
|
m_currentMode = RealMode;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
TransportDialog::displayTime()
|
|
{
|
|
switch (m_currentMode) {
|
|
case RealMode:
|
|
m_clearMetronomeTimer->stop();
|
|
m_transport->TimeDisplayLabel->hide();
|
|
break;
|
|
|
|
case SMPTEMode:
|
|
m_clearMetronomeTimer->stop();
|
|
m_transport->TimeDisplayLabel->setText("SMPTE"); // DO NOT i18n
|
|
m_transport->TimeDisplayLabel->show();
|
|
break;
|
|
|
|
case BarMode:
|
|
m_clearMetronomeTimer->stop();
|
|
m_transport->TimeDisplayLabel->setText("BAR"); // DO NOT i18n
|
|
m_transport->TimeDisplayLabel->show();
|
|
break;
|
|
|
|
case BarMetronomeMode:
|
|
m_clearMetronomeTimer->start(1700, FALSE);
|
|
m_transport->TimeDisplayLabel->setText("MET"); // DO NOT i18n
|
|
m_transport->TimeDisplayLabel->show();
|
|
break;
|
|
|
|
case FrameMode:
|
|
m_clearMetronomeTimer->stop();
|
|
m_transport->TimeDisplayLabel->setText(TQString("%1").arg(m_sampleRate));
|
|
m_transport->TimeDisplayLabel->show();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
TransportDialog::setNewMode(const std::string& newModeAsString)
|
|
{
|
|
TimeDisplayMode newMode = RealMode; // default value if not found
|
|
|
|
std::map<std::string, TimeDisplayMode>::iterator iter =
|
|
m_modeMap.find(newModeAsString);
|
|
|
|
if (iter != m_modeMap.end()) {
|
|
// value found
|
|
newMode = iter->second;
|
|
} else {
|
|
// don't fail: use default value set at declaration
|
|
}
|
|
|
|
setNewMode(newMode);
|
|
}
|
|
|
|
void
|
|
TransportDialog::setNewMode(const TimeDisplayMode& newMode)
|
|
{
|
|
computeSampleRate();
|
|
|
|
m_currentMode = newMode;
|
|
|
|
displayTime();
|
|
}
|
|
|
|
|
|
void
|
|
TransportDialog::slotChangeTimeDisplay()
|
|
{
|
|
computeSampleRate();
|
|
|
|
cycleThroughModes();
|
|
|
|
displayTime();
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotChangeToEnd()
|
|
{
|
|
if (m_transport->ToEndButton->isOn()) {
|
|
m_transport->ToEndLabel->show();
|
|
} else {
|
|
m_transport->ToEndLabel->hide();
|
|
}
|
|
}
|
|
|
|
bool
|
|
TransportDialog::isShowingTimeToEnd()
|
|
{
|
|
return m_transport->ToEndButton->isOn();
|
|
}
|
|
|
|
void
|
|
TransportDialog::displayRealTime(const RealTime &rt)
|
|
{
|
|
RealTime st = rt;
|
|
|
|
slotResetBackground();
|
|
|
|
if (m_lastMode != RealMode) {
|
|
m_transport->HourColonPixmap->show();
|
|
m_transport->MinuteColonPixmap->show();
|
|
m_transport->SecondColonPixmap->hide();
|
|
m_transport->HundredthColonPixmap->hide();
|
|
m_lastMode = RealMode;
|
|
}
|
|
|
|
// If time is negative then reverse the time and set the minus flag
|
|
//
|
|
if (st < RealTime::zeroTime) {
|
|
st = RealTime::zeroTime - st;
|
|
if (!m_lastNegative) {
|
|
m_transport->NegativePixmap->setPixmap(m_lcdNegative);
|
|
m_lastNegative = true;
|
|
}
|
|
} else // don't show the flag
|
|
{
|
|
if (m_lastNegative) {
|
|
m_transport->NegativePixmap->clear();
|
|
m_lastNegative = false;
|
|
}
|
|
}
|
|
|
|
m_tenThousandths = ( st.usec() / 100 ) % 10;
|
|
m_thousandths = ( st.usec() / 1000 ) % 10;
|
|
m_hundreths = ( st.usec() / 10000 ) % 10;
|
|
m_tenths = ( st.usec() / 100000 ) % 10;
|
|
|
|
m_unitSeconds = ( st.sec ) % 10;
|
|
m_tenSeconds = ( st.sec / 10 ) % 6;
|
|
|
|
m_unitMinutes = ( st.sec / 60 ) % 10;
|
|
m_tenMinutes = ( st.sec / 600 ) % 6;
|
|
|
|
m_unitHours = ( st.sec / 3600 ) % 10;
|
|
m_tenHours = (st.sec / 36000 ) % 10;
|
|
|
|
updateTimeDisplay();
|
|
}
|
|
|
|
void
|
|
TransportDialog::displayFrameTime(const RealTime &rt)
|
|
{
|
|
RealTime st = rt;
|
|
|
|
slotResetBackground();
|
|
|
|
if (m_lastMode != FrameMode) {
|
|
m_transport->HourColonPixmap->hide();
|
|
m_transport->MinuteColonPixmap->hide();
|
|
m_transport->SecondColonPixmap->hide();
|
|
m_transport->HundredthColonPixmap->hide();
|
|
m_lastMode = FrameMode;
|
|
}
|
|
|
|
// If time is negative then reverse the time and set the minus flag
|
|
//
|
|
if (st < RealTime::zeroTime) {
|
|
st = RealTime::zeroTime - st;
|
|
if (!m_lastNegative) {
|
|
m_transport->NegativePixmap->setPixmap(m_lcdNegative);
|
|
m_lastNegative = true;
|
|
}
|
|
} else // don't show the flag
|
|
{
|
|
if (m_lastNegative) {
|
|
m_transport->NegativePixmap->clear();
|
|
m_lastNegative = false;
|
|
}
|
|
}
|
|
|
|
long frame = RealTime::realTime2Frame(st, m_sampleRate);
|
|
|
|
m_tenThousandths = frame % 10;
|
|
frame /= 10;
|
|
m_thousandths = frame % 10;
|
|
frame /= 10;
|
|
m_hundreths = frame % 10;
|
|
frame /= 10;
|
|
m_tenths = frame % 10;
|
|
frame /= 10;
|
|
m_unitSeconds = frame % 10;
|
|
frame /= 10;
|
|
m_tenSeconds = frame % 10;
|
|
frame /= 10;
|
|
m_unitMinutes = frame % 10;
|
|
frame /= 10;
|
|
m_tenMinutes = frame % 10;
|
|
frame /= 10;
|
|
m_unitHours = frame % 10;
|
|
frame /= 10;
|
|
m_tenHours = frame % 10;
|
|
frame /= 10;
|
|
|
|
updateTimeDisplay();
|
|
}
|
|
|
|
void
|
|
TransportDialog::displaySMPTETime(const RealTime &rt)
|
|
{
|
|
RealTime st = rt;
|
|
|
|
slotResetBackground();
|
|
|
|
if (m_lastMode != SMPTEMode) {
|
|
m_transport->HourColonPixmap->show();
|
|
m_transport->MinuteColonPixmap->show();
|
|
m_transport->SecondColonPixmap->show();
|
|
m_transport->HundredthColonPixmap->show();
|
|
m_lastMode = SMPTEMode;
|
|
}
|
|
|
|
// If time is negative then reverse the time and set the minus flag
|
|
//
|
|
if (st < RealTime::zeroTime) {
|
|
st = RealTime::zeroTime - st;
|
|
if (!m_lastNegative) {
|
|
m_transport->NegativePixmap->setPixmap(m_lcdNegative);
|
|
m_lastNegative = true;
|
|
}
|
|
} else // don't show the flag
|
|
{
|
|
if (m_lastNegative) {
|
|
m_transport->NegativePixmap->clear();
|
|
m_lastNegative = false;
|
|
}
|
|
}
|
|
|
|
m_tenThousandths =
|
|
(( st.usec() * m_framesPerSecond * m_bitsPerFrame) / 1000000 ) % 10;
|
|
m_thousandths =
|
|
(( st.usec() * m_framesPerSecond * m_bitsPerFrame) / 10000000 ) %
|
|
(m_bitsPerFrame / 10);
|
|
m_hundreths =
|
|
(( st.usec() * m_framesPerSecond) / 1000000 ) % 10;
|
|
m_tenths =
|
|
(( st.usec() * m_framesPerSecond) / 10000000 ) % 10;
|
|
|
|
m_unitSeconds = ( st.sec ) % 10;
|
|
m_tenSeconds = ( st.sec / 10 ) % 6;
|
|
|
|
m_unitMinutes = ( st.sec / 60 ) % 10;
|
|
m_tenMinutes = ( st.sec / 600 ) % 6;
|
|
|
|
m_unitHours = ( st.sec / 3600 ) % 10;
|
|
m_tenHours = ( st.sec / 36000 ) % 10;
|
|
|
|
updateTimeDisplay();
|
|
}
|
|
|
|
void
|
|
TransportDialog::displayBarTime(int bar, int beat, int unit)
|
|
{
|
|
if (m_lastMode != BarMode) {
|
|
m_transport->HourColonPixmap->hide();
|
|
m_transport->MinuteColonPixmap->show();
|
|
m_transport->SecondColonPixmap->hide();
|
|
m_transport->HundredthColonPixmap->hide();
|
|
m_lastMode = BarMode;
|
|
}
|
|
|
|
// If time is negative then reverse the time and set the minus flag
|
|
//
|
|
if (bar < 0) {
|
|
bar = -bar;
|
|
if (!m_lastNegative) {
|
|
m_transport->NegativePixmap->setPixmap(m_lcdNegative);
|
|
m_lastNegative = true;
|
|
}
|
|
} else // don't show the flag
|
|
{
|
|
if (m_lastNegative) {
|
|
m_transport->NegativePixmap->clear();
|
|
m_lastNegative = false;
|
|
}
|
|
}
|
|
|
|
if (m_currentMode == BarMetronomeMode && unit < 2) {
|
|
if (beat == 1) {
|
|
slotSetBackground(TQt::red);
|
|
} else {
|
|
slotSetBackground(TQt::cyan);
|
|
}
|
|
} else {
|
|
slotResetBackground();
|
|
}
|
|
|
|
m_tenThousandths = ( unit ) % 10;
|
|
m_thousandths = ( unit / 10 ) % 10;
|
|
m_hundreths = ( unit / 100 ) % 10;
|
|
m_tenths = ( unit / 1000 ) % 10;
|
|
|
|
if (m_tenths == 0) {
|
|
m_tenths = -1;
|
|
if (m_hundreths == 0) {
|
|
m_hundreths = -1;
|
|
if (m_thousandths == 0) {
|
|
m_thousandths = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_unitSeconds = ( beat ) % 10;
|
|
m_tenSeconds = ( beat / 10 ) % 6;
|
|
|
|
if (m_tenSeconds == 0) {
|
|
m_tenSeconds = -1;
|
|
}
|
|
|
|
m_unitMinutes = ( bar ) % 10;
|
|
m_tenMinutes = ( bar / 10 ) % 10;
|
|
|
|
m_unitHours = ( bar / 100 ) % 10;
|
|
m_tenHours = ( bar / 1000 ) % 10;
|
|
|
|
if (m_tenHours == 0) {
|
|
m_tenHours = -1;
|
|
if (m_unitHours == 0) {
|
|
m_unitHours = -1;
|
|
if (m_tenMinutes == 0) {
|
|
m_tenMinutes = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
updateTimeDisplay();
|
|
}
|
|
|
|
void
|
|
TransportDialog::updateTimeDisplay()
|
|
{
|
|
if (m_tenThousandths != m_lastTenThousandths) {
|
|
if (m_tenThousandths < 0)
|
|
m_transport->TenThousandthsPixmap->clear();
|
|
else
|
|
m_transport->TenThousandthsPixmap->setPixmap(m_lcdList[m_tenThousandths]);
|
|
m_lastTenThousandths = m_tenThousandths;
|
|
}
|
|
|
|
if (m_thousandths != m_lastThousandths) {
|
|
if (m_thousandths < 0)
|
|
m_transport->ThousandthsPixmap->clear();
|
|
else
|
|
m_transport->ThousandthsPixmap->setPixmap(m_lcdList[m_thousandths]);
|
|
m_lastThousandths = m_thousandths;
|
|
}
|
|
|
|
if (m_hundreths != m_lastHundreths) {
|
|
if (m_hundreths < 0)
|
|
m_transport->HundredthsPixmap->clear();
|
|
else
|
|
m_transport->HundredthsPixmap->setPixmap(m_lcdList[m_hundreths]);
|
|
m_lastHundreths = m_hundreths;
|
|
}
|
|
|
|
if (m_tenths != m_lastTenths) {
|
|
if (m_tenths < 0)
|
|
m_transport->TenthsPixmap->clear();
|
|
else
|
|
m_transport->TenthsPixmap->setPixmap(m_lcdList[m_tenths]);
|
|
m_lastTenths = m_tenths;
|
|
}
|
|
|
|
if (m_unitSeconds != m_lastUnitSeconds) {
|
|
if (m_unitSeconds < 0)
|
|
m_transport->UnitSecondsPixmap->clear();
|
|
else
|
|
m_transport->UnitSecondsPixmap->setPixmap(m_lcdList[m_unitSeconds]);
|
|
m_lastUnitSeconds = m_unitSeconds;
|
|
}
|
|
|
|
if (m_tenSeconds != m_lastTenSeconds) {
|
|
if (m_tenSeconds < 0)
|
|
m_transport->TenSecondsPixmap->clear();
|
|
else
|
|
m_transport->TenSecondsPixmap->setPixmap(m_lcdList[m_tenSeconds]);
|
|
m_lastTenSeconds = m_tenSeconds;
|
|
}
|
|
|
|
if (m_unitMinutes != m_lastUnitMinutes) {
|
|
if (m_unitMinutes < 0)
|
|
m_transport->UnitMinutesPixmap->clear();
|
|
else
|
|
m_transport->UnitMinutesPixmap->setPixmap(m_lcdList[m_unitMinutes]);
|
|
m_lastUnitMinutes = m_unitMinutes;
|
|
}
|
|
|
|
if (m_tenMinutes != m_lastTenMinutes) {
|
|
if (m_tenMinutes < 0)
|
|
m_transport->TenMinutesPixmap->clear();
|
|
else
|
|
m_transport->TenMinutesPixmap->setPixmap(m_lcdList[m_tenMinutes]);
|
|
m_lastTenMinutes = m_tenMinutes;
|
|
}
|
|
|
|
if (m_unitHours != m_lastUnitHours) {
|
|
if (m_unitHours < 0)
|
|
m_transport->UnitHoursPixmap->clear();
|
|
else
|
|
m_transport->UnitHoursPixmap->setPixmap(m_lcdList[m_unitHours]);
|
|
m_lastUnitHours = m_unitHours;
|
|
}
|
|
|
|
if (m_tenHours != m_lastTenHours) {
|
|
if (m_tenHours < 0)
|
|
m_transport->TenHoursPixmap->clear();
|
|
else
|
|
m_transport->TenHoursPixmap->setPixmap(m_lcdList[m_tenHours]);
|
|
m_lastTenHours = m_tenHours;
|
|
}
|
|
}
|
|
|
|
void
|
|
TransportDialog::setTempo(const tempoT &tempo)
|
|
{
|
|
if (m_tempo == tempo)
|
|
return ;
|
|
m_tempo = tempo;
|
|
|
|
// Send the quarter note length to the sequencer - shouldn't
|
|
// really hang this off here but at least it's a single point
|
|
// where the tempo should always be consistent. Quarter Note
|
|
// Length is sent (MIDI CLOCK) at 24ppqn.
|
|
//
|
|
double qnD = 60.0 / Composition::getTempoQpm(tempo);
|
|
RealTime qnTime =
|
|
RealTime(long(qnD),
|
|
long((qnD - double(long(qnD))) * 1000000000.0));
|
|
|
|
StudioControl::sendQuarterNoteLength(qnTime);
|
|
|
|
TQString tempoString;
|
|
tempoString.sprintf("%4.3f", Composition::getTempoQpm(tempo));
|
|
|
|
m_transport->TempoDisplay->setText(tempoString);
|
|
}
|
|
|
|
void
|
|
TransportDialog::setTimeSignature(const TimeSignature &timeSig)
|
|
{
|
|
int numerator = timeSig.getNumerator();
|
|
int denominator = timeSig.getDenominator();
|
|
if (m_numerator == numerator && m_denominator == denominator)
|
|
return ;
|
|
m_numerator = numerator;
|
|
m_denominator = denominator;
|
|
|
|
TQString timeSigString;
|
|
timeSigString.sprintf("%d/%d", numerator, denominator);
|
|
m_transport->TimeSigDisplay->setText(timeSigString);
|
|
}
|
|
|
|
void
|
|
TransportDialog::setMidiInLabel(const MappedEvent *mE)
|
|
{
|
|
assert(mE > 0);
|
|
|
|
switch (mE->getType()) {
|
|
case MappedEvent::MidiNote:
|
|
case MappedEvent::MidiNoteOneShot:
|
|
{
|
|
// don't do anything if we've got an effective NOTE OFF
|
|
//
|
|
if (mE->getVelocity() == 0)
|
|
return ;
|
|
|
|
MidiPitchLabel mPL(mE->getPitch());
|
|
m_transport->InDisplay->setText
|
|
(mPL.getTQString() +
|
|
TQString(" %1").arg(mE->getVelocity()));
|
|
}
|
|
break;
|
|
|
|
case MappedEvent::MidiPitchBend:
|
|
m_transport->InDisplay->setText(i18n("PITCH WHEEL"));
|
|
break;
|
|
|
|
case MappedEvent::MidiController:
|
|
m_transport->InDisplay->setText(i18n("CONTROLLER"));
|
|
break;
|
|
|
|
case MappedEvent::MidiProgramChange:
|
|
m_transport->InDisplay->setText(i18n("PROG CHNGE"));
|
|
break;
|
|
|
|
case MappedEvent::MidiKeyPressure:
|
|
case MappedEvent::MidiChannelPressure:
|
|
m_transport->InDisplay->setText(i18n("PRESSURE"));
|
|
break;
|
|
|
|
case MappedEvent::MidiSystemMessage:
|
|
m_transport->InDisplay->setText(i18n("SYS MESSAGE"));
|
|
break;
|
|
|
|
default: // do nothing
|
|
return ;
|
|
}
|
|
|
|
// Reset the timer if it's already running
|
|
//
|
|
if (m_midiInTimer->isActive())
|
|
m_midiInTimer->stop();
|
|
|
|
// 1.5 second timeout for MIDI event
|
|
//
|
|
m_midiInTimer->start(1500, true);
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotClearMidiInLabel()
|
|
{
|
|
m_transport->InDisplay->setText(i18n(TQString("NO EVENTS").ascii()));
|
|
|
|
// also, just to be sure:
|
|
slotResetBackground();
|
|
}
|
|
|
|
void
|
|
TransportDialog::setMidiOutLabel(const MappedEvent *mE)
|
|
{
|
|
assert(mE > 0);
|
|
|
|
switch (mE->getType()) {
|
|
case MappedEvent::MidiNote:
|
|
case MappedEvent::MidiNoteOneShot:
|
|
{
|
|
MidiPitchLabel mPL(mE->getPitch());
|
|
m_transport->OutDisplay->setText
|
|
(mPL.getTQString() +
|
|
TQString(" %1").arg(mE->getVelocity()));
|
|
}
|
|
break;
|
|
|
|
case MappedEvent::MidiPitchBend:
|
|
m_transport->OutDisplay->setText(i18n("PITCH WHEEL"));
|
|
break;
|
|
|
|
case MappedEvent::MidiController:
|
|
m_transport->OutDisplay->setText(i18n("CONTROLLER"));
|
|
break;
|
|
|
|
case MappedEvent::MidiProgramChange:
|
|
m_transport->OutDisplay->setText(i18n("PROG CHNGE"));
|
|
break;
|
|
|
|
case MappedEvent::MidiKeyPressure:
|
|
case MappedEvent::MidiChannelPressure:
|
|
m_transport->OutDisplay->setText(i18n("PRESSURE"));
|
|
break;
|
|
|
|
case MappedEvent::MidiSystemMessage:
|
|
m_transport->OutDisplay->setText(i18n("SYS MESSAGE"));
|
|
break;
|
|
|
|
default: // do nothing
|
|
return ;
|
|
}
|
|
|
|
// Reset the timer if it's already running
|
|
//
|
|
if (m_midiOutTimer->isActive())
|
|
m_midiOutTimer->stop();
|
|
|
|
// 200 millisecond timeout
|
|
//
|
|
m_midiOutTimer->start(200, true);
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotClearMidiOutLabel()
|
|
{
|
|
m_transport->OutDisplay->setText(i18n(TQString("NO EVENTS").ascii()));
|
|
}
|
|
|
|
void
|
|
TransportDialog::closeEvent (TQCloseEvent * /*e*/)
|
|
{
|
|
//e->accept(); // accept the close event here
|
|
emit closed();
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotLoopButtonClicked()
|
|
{
|
|
// disable if JACK transport has been set #1240039 - DMM
|
|
// TDEConfig* config = rgapp->config();
|
|
// config->setGroup(SequencerOptionsConfigGroup);
|
|
// if (config->readBoolEntry("jacktransport", false))
|
|
// {
|
|
// //!!! - this will fail silently
|
|
// m_transport->LoopButton->setEnabled(false);
|
|
// m_transport->LoopButton->setOn(false);
|
|
// return;
|
|
// }
|
|
|
|
if (m_transport->LoopButton->isOn()) {
|
|
emit setLoop();
|
|
} else {
|
|
emit unsetLoop();
|
|
}
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotSetStartLoopingPointAtMarkerPos()
|
|
{
|
|
emit setLoopStartTime();
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotSetStopLoopingPointAtMarkerPos()
|
|
{
|
|
emit setLoopStopTime();
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotPanelOpenButtonClicked()
|
|
{
|
|
int rfh = m_transport->RecordingFrame->height();
|
|
|
|
if (m_transport->RecordingFrame->isVisible()) {
|
|
m_transport->RecordingFrame->hide();
|
|
setFixedSize(width(), height() - rfh);
|
|
m_transport->PanelOpenButton->setPixmap(m_panelClosed);
|
|
m_isExpanded = false;
|
|
} else {
|
|
setFixedSize(width(), height() + rfh);
|
|
m_transport->RecordingFrame->show();
|
|
m_transport->PanelOpenButton->setPixmap(m_panelOpen);
|
|
m_isExpanded = true;
|
|
}
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotPanelCloseButtonClicked()
|
|
{
|
|
int rfh = m_transport->RecordingFrame->height();
|
|
|
|
if (m_transport->RecordingFrame->isVisible()) {
|
|
m_transport->RecordingFrame->hide();
|
|
setFixedSize(width(), height() - rfh);
|
|
m_transport->PanelOpenButton->setPixmap(m_panelClosed);
|
|
m_isExpanded = false;
|
|
}
|
|
}
|
|
|
|
bool
|
|
TransportDialog::isExpanded()
|
|
{
|
|
return m_isExpanded;
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotEditTempo()
|
|
{
|
|
emit editTempo(this);
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotEditTimeSignature()
|
|
{
|
|
emit editTimeSignature(this);
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotEditTime()
|
|
{
|
|
emit editTransportTime(this);
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotSetBackground(TQColor c)
|
|
{
|
|
if (!m_haveOriginalBackground) {
|
|
m_originalBackground = m_transport->LCDBoxFrame->paletteBackgroundColor();
|
|
m_haveOriginalBackground = true;
|
|
}
|
|
|
|
m_transport->LCDBoxFrame->setPaletteBackgroundColor(c);
|
|
m_transport->NegativePixmap->setPaletteBackgroundColor(c);
|
|
m_transport->TenHoursPixmap->setPaletteBackgroundColor(c);
|
|
m_transport->UnitHoursPixmap->setPaletteBackgroundColor(c);
|
|
m_transport->TimeDisplayLabel->setPaletteBackgroundColor(c);
|
|
|
|
/* this is a bit more thorough, but too slow and flickery:
|
|
|
|
const TQObjectList *children = m_transport->LCDBoxFrame->children();
|
|
TQObjectListIt it(*children);
|
|
TQObject *obj;
|
|
|
|
while ((obj = it.current()) != 0) {
|
|
|
|
TQWidget *w = dynamic_cast<TQWidget *>(obj);
|
|
if (w) {
|
|
w->setPaletteBackgroundColor(c);
|
|
}
|
|
++it;
|
|
}
|
|
|
|
*/
|
|
|
|
m_isBackgroundSet = true;
|
|
}
|
|
|
|
void
|
|
TransportDialog::slotResetBackground()
|
|
{
|
|
if (m_isBackgroundSet) {
|
|
slotSetBackground(m_originalBackground);
|
|
}
|
|
m_isBackgroundSet = false;
|
|
}
|
|
|
|
}
|
|
#include "TransportDialog.moc"
|