1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
|
// -*- c-basic-offset: 4 -*-
/*
Rosegarden-4
A sequencer and musical notation editor.
This program is Copyright 2000-2005
Guillaume Laurent <glaurent@telegraph-road.org>,
Chris Cannam <cannam@all-day-breakfast.com>,
Richard Bown <bownie@bownie.com>
The moral right of the authors to claim authorship of this work
has been asserted.
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 <qtimer.h>
#include <sys/time.h>
#include "RealTime.h"
#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <klocale.h>
#include <dcopclient.h>
#include <kconfig.h>
#include <kmessagebox.h>
#include <kstddirs.h>
#include <ktip.h>
#include <kprocess.h>
#include "constants.h"
#include "rosestrings.h"
#include "rosedebug.h"
#include "rosegardengui.h"
#include "rosegardenguidoc.h"
#include "kstartuplogo.h"
#include "rgapplication.h"
#include "config.h"
/*! \mainpage Rosegarden-4 global design
Rosegarden is split into 3 main parts:
\section base Base
The base library holds all of the fundamental "music handling"
structures, of which the primary ones are Event, Segment, Track,
Instrument and Composition. It also contains a selection of utility
and helper classes of a kind that is not specific to any particular
GUI. Everything here is part of the Rosegarden namespace, and there
are no dependencies on KDE or Qt (although it uses the STL heavily).
The keyword for the basic structures in use is "flexibility". Our
Event objects can be extended arbitrarily for the convenience of GUI
or performance code without having to change their declaration or
modify anything in the base library. And most of our assumptions
about the use of the container classes can be violated without
disastrous side-effects.
\subsection musicstructs Music Structures
- \link Rosegarden::Event Event\endlink is the basic musical element. It's more or less a
generalization of the MIDI event. Each note or rest, each key
change or tempo change, is an event: there's no "note class" or
"rest class" as such, they are simply represented by events whose
type happens to be "note" or "rest".
Each Event has a type code, absolute time (the moment at which the
Event starts, relative only to the start of the Composition) and
duration (usually non-zero only for notes and rests), together
with an arbitrary set of named and typed properties that can be
assigned and queried dynamically by other parts of the
application. So, for example, a note event is likely to have an
integer property called "pitch", and probably a "velocity", as
well as potentially many others -- but this is not fixed anywhere,
and there's no definition of what exactly a note is: client code
is simply expected to ignore any unrecognised events or properties
and to cope if properties that should be there are not.
- \link Rosegarden::Segment Segment\endlink is a series of consecutive Events found on the same Track,
automatically ordered by their absolute time. It's the usual
container for Events. A Segment has a starting time that can be
changed, and a duration that is based solely on the end time of
the last Event it contains. Note that in order to facilitate
musical notation editing, we explicitly store silences as series
of rest Events; thus a Segment really should contain no gaps
between its Events. (This isn't checked anywhere and nothing will
break very badly if there are gaps, but notation won't quite work
correctly.)
- \link Rosegarden::Track Track \endlink is much the same thing as on a mixing table, usually
assigned to an instrument, a voice, etc. Although a Track is not
a container of Events and is not strictly a container of Segments
either, it is referred to by a set of Segments that are therefore
mutually associated with the same instruments and parameters. In
GUI terms, the Track is a horizontal row on the main Rosegarden
window, whereas a Segment is a single blue box within that row, of
which there may be any number.
- \link Rosegarden::Instrument Instrument \endlink corresponds broadly to a MIDI or Audio channel, and is
the destination for a performed Event. Each Track is mapped to a
single Instrument (although many Tracks may have the same
Instrument), and the Instrument is indicated in the header at the
left of the Track's row in the GUI.
- \link Rosegarden::Composition Composition\endlink is the container for the entire piece of music. It
consists of a set of Segments, together with a set of Tracks that
the Segments may or may not be associated with, a set of
Instruments, and some information about time signature and tempo
changes. (The latter are not stored in Segments; they are only
stored in the top-level Composition. You can't have differing
time signatures or tempos in different Segments.) Any code that
wants to know about the locations of bar lines, or request
real-time calculations based on tempo changes, talks to the
Composition.
See also docs/data_struct/units.txt for an explanation of the units we
use for time and pitch values. See docs/discussion/names.txt for some
name-related discussion. See docs/code/creating_events.txt for an
explanation of how to create new Events and add properties to them.
The base directory also contains various music-related helper classes:
- The NotationTypes.[Ch] files contain classes that help with
creating and manipulating events. It's very important to realise
that these classes are not the events themselves: although there
is a Note class in this file, and a TimeSignature class, and Clef
and Key classes, instances of these are rarely stored anywhere.
Instead they're created on-the-fly in order to do calculation
related to note durations or time signatures or whatever, and they
contain getAsEvent() methods that may be used when an event for
storage is required. But the class of a stored event is always
simply Event.
The NotationTypes classes also define important constants for the
names of common properties in Events. For example, the Note class
contains Note::EventType, which is the type of a note Event, and
Note::EventRestType, the type of a rest Event; and Key contains
Key::EventType, the type of a key change Event, KeyPropertyName,
the name of the property that defines the key change, and a set
of the valid strings for key changes.
- BaseProperties.[Ch] contains a set of "standard"-ish Event
property names that are not basic enough to go in NotationTypes.
- \link Rosegarden::SegmentNotationHelper SegmentNotationHelper\endlink
and \link Rosegarden::SegmentPerformanceHelper SegmentPerformanceHelper\endlink
do tasks that
may be useful to notation-type code and performer code
respectively. For example, SegmentNotationHelper is used to
manage rests when inserting and deleting notes in a score editor,
and to create beamed groups and suchlike; SegmentPerformanceHelper
generally does calculations involving real performance time of
notes (taking into account tied notes, tuplets and tempo changes).
These two lightweight helper classes are also usually constructed
on-the-fly for use on the events in a given Segment and then
discarded after use.
- \link Rosegarden::Quantizer Quantizer\endlink is used to quantize event timings and set quantized
timing properties on those events. Note that quantization is
non-destructive, as it takes advantage of the ability to set new
Event properties to simply assign the quantized values as separate
properties from the original absolute time and duration.
\section gui GUI
The GUI directory builds into a KDE/Qt application. Like most KDE
applications, it follows a document/view model. The document (class
RosegardenGUIDoc, which wraps a Composition) can have several views
(class RosegardenGUIView), although at the moment only a single one is
used.
This view is the TrackEditor, which shows all the Composition's
Segments organized in Tracks. Each Segment can be edited in two ways:
notation (score) or matrix (piano roll).
All editor views are derived from EditView. An EditView is the class
dealing with the edition per se of the events. It uses several
components:
- Layout classes, horizontal and vertical: these are the classes
which determine the x and y coordinates of the graphic items
representing the events (notes or piano-roll rectangles). They
are derived from the LayoutEngine base-class in the base library.
- Tools, which implement each editing function at the GUI (such as
insert, erase, cut and paste). These are the tools which appear on
the EditView's toolbar.
- Toolbox, which is a simple string => tool map.
- Commands, which are the fundamental implementations of editing
operations (both menu functions and tool operations) subclassed
from KDE's Command and used for undo and redo.
- a canvas view. Although this isn't a part of the EditView's
definition, both of the existing edit views (notation and matrix)
use one, because they both use a QCanvas to represent data.
- LinedStaff, a staff with lines. Like the canvas view, this isn't
part of the EditView definition, but both views use one.
There are currently two editor views:
- NotationView, with accompanying classes NotationHLayout,
NotationVLayout, NotationStaff, and all the classes in the
notationtool and notationcommands files. These are also closely
associated with the NotePixmapFactory and NoteFont classes, which
are used to generate notes from component pixmap files.
- MatrixView, with accompanying classes MatrixHLayout,
MatrixVLayout, MatrixStaff and other classes in the matrixview
files.
The editing process works as follows:
[NOTE : in the following, we're talking both about events as UI events
or user events (mouse button clicks, mouse move, keystrokes, etc...)
and Events (our basic music element). To help lift the ambiguity,
"events" is for UI events, Events is for Rosegarden::Event.]
-# The canvas view gets the user events (see
NotationCanvasView::contentsMousePressEvent(QMouseEvent*) for an
example). It locates where the event occured in terms of musical
element: which note or staff line the user clicked on, which pitch
and time this corresponds to, that kind of stuff. (In the
Notation and Matrix views, the LinedStaff calculates mappings
between coordinates and staff lines: the former is especially
complicated because of its support for page layout.)\n
-# The canvas view transmits this kind of info as a signal, which is
connected to a slot in the parent EditView.
-# The EditView delegates action to the current tool.\n
-# The tool performs the actual job (inserting or deleting a note,
etc...).
Since this action is usually complex (merely inserting a note requires
dealing with the surrounding Events, rests or notes), it does it
through a SegmentHelper (for instance, base/SegmentNotationHelper)
which "wraps" the complexity into simple calls and performs all the
hidden tasks.
The EditView also maintains (obviously) its visual appearance with the
layout classes, applying them when appropriate.
\section sequencer Sequencer
The sequencer directory also builds into a KDE/Qt application, but one
which doesn't have a gui. The Sequencer can be started automatically
by the main Rosegarden GUI or manually if testing - it's sometimes
more convenient to do the latter as the Sequencer needs to be connected
up to the underlying sound system every time it is started.
The Sequencer interfaces with aRTS (www.arts-project.org) sound system
and provides MIDI "play" and "record" ports which can be connected to
other MIDI clients (MIDI IN and OUT hardware ports or aRTS synth devices)
using the aRTS Midi Manager. The Sequencer will also eventually support
playing and recording of Audio sample files.
The GUI and Sequencer communicate using the KDE DCOP communication framework.
Look in:
rosegarden/gui/rosegardenguiiface.h
rosegarden/sequencer/rosegardensequenceriface.h
for definitions of the DCOP interfaces pertinent to the Sequencer
and GUI. The main DCOP operations from the GUI involve starting and
stopping the Sequencer, playing and recording, fast forwarding and
rewinding. Once a play or record cycle is enabled it's the Sequencer
that does most of the hard work. To service a play() command the
Sequencer fetches a slice of Events from the Rosegarden Composition
(see getSequencerSlice()) and queues them up with the aRTS MidiEvent
dispatcher. Interlaced within the main Sequencer loop is a call
which also services pending incoming MIDI events from the Rosegarden
record port and forwards them upwards to the GUI.
The Rosegarden record port is built around a specialisation of the
Arts::MidiPort - see rosegarden/sequencer/MidiArts.idl for the
interface definition and check out the rosegarden/sequencer/Makefile.am
for how it gets built. This record port has to be run as part of the aRTS
sound server - check out the documentation in:
rosegarden/docs/howtos/artsd-mcop-notes
for more information about how to get this working.
The Sequencer makes use of two libraries libRosegardenSequencer
and libRosegardenSound:
- libRosegardenSequencer holds everything pertinent to sequencing
for Rosegarden including the aRTS MCOP record interface and the
Sequencer class itself. This library is only linked into the
Rosegarden Sequencer.
- libRosegardenSound holds the MidiFile class (writing and reading
MIDI files) and the MappedEvent and MappedComposition classes (the
communication class for transferring events back and forth across
DCOP). This library is needed by the GUI as well as the Sequencer.
The main Sequencer state machine is a good starting point and clearly
visible at the bottom of rosegarden/sequencer/main.cpp.
*/
static const char *description =
I18N_NOOP("Rosegarden - A sequencer and musical notation editor");
static KCmdLineOptions options[] =
{
{ "nosequencer", I18N_NOOP("Don't use the sequencer (support editing only)"), 0 },
{ "nosplash", I18N_NOOP("Don't show the splash screen"), 0 },
{ "nofork", I18N_NOOP("Don't automatically run in the background"), 0 },
{ "existingsequencer", I18N_NOOP("Attach to a running sequencer process, if found"), 0 },
{ "+[File]", I18N_NOOP("file to open"), 0 },
{ 0, 0, 0 }
};
// -----------------------------------------------------------------
#ifdef Q_WS_X11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/SM/SMlib.h>
static int _x_errhandler( Display *dpy, XErrorEvent *err )
{
char errstr[256];
XGetErrorText( dpy, err->error_code, errstr, 256 );
if ( err->error_code != BadWindow )
kdWarning() << "Rosegarden: detected X Error: " << errstr << " " << err->error_code
<< "\n Major opcode: " << err->request_code << endl;
return 0;
}
#endif
void testInstalledVersion()
{
QString versionLocation = locate("appdata", "version.txt");
QString installedVersion;
if (versionLocation) {
QFile versionFile(versionLocation);
if (versionFile.open(IO_ReadOnly)) {
QTextStream text(&versionFile);
QString s = text.readLine().stripWhiteSpace();
versionFile.close();
if (s) {
if (s == VERSION) return;
installedVersion = s;
}
}
}
if (installedVersion) {
KMessageBox::detailedError
(0,
i18n("Installation contains the wrong version of Rosegarden."),
i18n(" The wrong versions of Rosegarden's data files were\n"
" found in the standard KDE installation directories.\n"
" (I am %1, but the installed files are for version %2.)\n\n"
" This may mean one of the following:\n\n"
" 1. This is a new upgrade of Rosegarden, and it has not yet been\n"
" installed. If you compiled it yourself, check that you have\n"
" run \"make install\" and that the procedure completed\n"
" successfully.\n\n"
" 2. The upgrade was installed in a non-standard directory,\n"
" and an old version was found in a standard directory. If so,\n"
" you will need to add the correct directory to your KDEDIRS\n"
" environment variable before you can run it.").arg(VERSION).arg(installedVersion),
i18n("Installation problem"));
} else {
KMessageBox::detailedError
(0,
i18n("Rosegarden does not appear to have been installed."),
i18n(" One or more of Rosegarden's data files could not be\n"
" found in the standard KDE installation directories.\n\n"
" This may mean one of the following:\n\n"
" 1. Rosegarden has not been correctly installed. If you compiled\n"
" it yourself, check that you have run \"make install\" and that\n"
" the procedure completed successfully.\n\n"
" 2. Rosegarden has been installed in a non-standard directory,\n"
" and you need to add this directory to your KDEDIRS environment\n"
" variable before you can run it. This may be the case if you\n"
" installed into $HOME or a local third-party package directory\n"
" like /usr/local or /opt."),
i18n("Installation problem"));
}
exit(1);
}
int main(int argc, char *argv[])
{
setsid(); // acquire shiny new process group
KAboutData aboutData( "rosegarden4", I18N_NOOP("Rosegarden4"),
VERSION, description, KAboutData::License_GPL,
I18N_NOOP("Copyright 2000 - 2005 Guillaume Laurent, Chris Cannam, Richard Bown\nParts copyright 1994 - 2004 Chris Cannam, Andy Green, Richard Bown, Guillaume Laurent\nLilypond fonts copyright 1997 - 2004 Han-Wen Nienhuys and Jan Nieuwenhuizen"),
0,
"http://www.rosegardenmusic.com/",
"rosegarden-devel@sf.net");
aboutData.addAuthor("Guillaume Laurent", 0, "glaurent@telegraph-road.org", "http://telegraph-road.org");
aboutData.addAuthor("Chris Cannam", 0, "cannam@all-day-breakfast.com", "http://all-day-breakfast.com");
aboutData.addAuthor("Richard Bown", 0, "bownie@bownie.com", "http://bownie.com");
aboutData.addCredit("Randall Farmer", I18N_NOOP("Chord labelling code"), " rfarme@simons-rock.edu");
aboutData.addCredit("Hans Kieserman", I18N_NOOP("Lilypond output\nassorted other patches\ni18n-ization"), "hkieserman@mail.com");
aboutData.addCredit("Michael McIntyre", I18N_NOOP("notation selection event filter\nextra toolbars/pixmaps\nnotation/Lilypond patches\nauthor of \"Using Rosegarden\""), "dmmcintyr@users.sourceforge.net");
aboutData.addCredit("Levi Burton", I18N_NOOP("UI improvements\nbug fixes"), "donburton@sbcglobal.net");
aboutData.addCredit("Alexandre Prokoudine", I18N_NOOP("Russian translation\ni18n-ization"), "avp@altlinux.ru");
aboutData.addCredit("Pedro Lopez-Cabanillas", I18N_NOOP("Spanish translation\nALSA hacking and bug fixes\nmulti-input MIDI recording"), "plcl@users.sourceforge.net");
aboutData.addCredit("Jörg Schumann", I18N_NOOP("German translation"), "jrschumann@gmx.de");
aboutData.addCredit("Kevin Donnelly", I18N_NOOP("Welsh translation"));
aboutData.addCredit("Didier Burli", I18N_NOOP("French translation"), "didierburli@bluewin.ch");
aboutData.addCredit("Daniele Medri", I18N_NOOP("Italian translation"), "madrid@linuxmeeting.net");
aboutData.addCredit("Alessandro Musesti", I18N_NOOP("Italian translation"), "a.musesti@dmf.unicatt.it");
aboutData.addCredit("Stefan Asserhäll", I18N_NOOP("Swedish translation"), "stefan.asserhall@comhem.se");
aboutData.addCredit("Hasso Tepper", I18N_NOOP("Estonian translation"), "hasso@estpak.ee");
aboutData.addCredit("Jelmer Vernooij", I18N_NOOP("Dutch translation"), "jelmer@samba.org");
aboutData.addCredit("Bernd Weber", I18N_NOOP("German translation (Arbeiten mit Rosegarden)"), "weber.freiburg@freenet.de");
aboutData.addCredit("Kevin Liang", I18N_NOOP("HSpinBox class"), "xkliang@rhpcs.mcmaster.ca");
aboutData.addCredit("Thorsten Wilms", I18N_NOOP("Original designs for rotary controllers"), "t_w_@freenet.de");
aboutData.addCredit("Oota Toshiya", I18N_NOOP("Japanese translation"), "ribbon@users.sourceforge.net");
aboutData.addCredit("William", I18N_NOOP("Auto-scroll deceleration\nRests outside staves and other bug fixes"), "rosegarden4p AT orthoset.com");
aboutData.addCredit("Liu Songhe", I18N_NOOP("Simplified Chinese translation"), "jackliu9999@msn.com");
aboutData.setTranslator(I18N_NOOP("_: NAME OF TRANSLATORS\nYour names") ,I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails"));
KCmdLineArgs::init( argc, argv, &aboutData );
KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
KUniqueApplication::addCmdLineOptions(); // Add KUniqueApplication options.
if (!RosegardenApplication::start()) return 0;
RosegardenApplication app;
// Give up immediately if we haven't been installed or if the
// installation is out of date
//
testInstalledVersion();
//
// Ensure quit on last window close
// Register main DCOP interface
//
QObject::connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
app.dcopClient()->registerAs(app.name(), false);
app.dcopClient()->setDefaultObject(ROSEGARDEN_GUI_IFACE_NAME);
// Parse cmd line args
//
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
// Show Startup logo
// (this code borrowed from KDevelop 2.0,
// (c) The KDevelop Development Team
//
KConfig* config = kapp->config();
config->setGroup(Rosegarden::GeneralOptionsConfigGroup);
KStartupLogo* startLogo = 0L;
// See if the config wants us to control JACK
//
if (config->readBoolEntry("Logo",true) && (!kapp->isRestored() && args->isSet("splash")) )
{
RG_DEBUG << "main: Showing startup logo\n";
startLogo = KStartupLogo::getInstance();
startLogo->show();
}
struct timeval logoShowTime;
gettimeofday(&logoShowTime, 0);
//
// Start application
//
RosegardenGUIApp *rosegardengui = 0;
if (app.isRestored()) {
// RESTORE(RosegardenGUIApp);
int n = 1;
while (KMainWindow::canBeRestored(n)) {
// memory leak if more than one can be restored?
(rosegardengui = new RosegardenGUIApp)->restore(n);
n++;
}
} else {
#ifndef NO_SOUND
app.setNoSequencerMode(!args->isSet("sequencer"));
#else
app.setNoSequencerMode(true);
#endif // NO_SOUND
rosegardengui = new RosegardenGUIApp(!app.noSequencerMode(),
args->isSet("existingsequencer"),
startLogo);
app.setMainWidget(rosegardengui);
rosegardengui->show();
// raise start logo
//
if (startLogo) {
startLogo->raise();
startLogo->setHideEnabled(true);
QApplication::flushX();
}
if (args->count()) {
rosegardengui->openFile(QFile::decodeName(args->arg(0)), RosegardenGUIApp::ImportCheckType);
} else {
// rosegardengui->openDocumentFile();
}
args->clear();
}
// Now that we've started up, raise start logo
//
if (startLogo) {
startLogo->raise();
startLogo->setHideEnabled(true);
QApplication::flushX();
}
// Check for sequencer and launch if needed
//
try
{
rosegardengui->launchSequencer(args->isSet("existingsequencer"));
}
catch(std::string e)
{
RG_DEBUG << "RosegardenGUI - " << e << endl;
}
catch(QString e)
{
RG_DEBUG << "RosegardenGUI - " << e << endl;
}
if (startLogo) {
// pause to ensure the logo has been visible for a reasonable
// length of time, just 'cos it looks a bit silly to show it
// and remove it immediately
struct timeval now;
gettimeofday(&now, 0);
Rosegarden::RealTime visibleFor =
Rosegarden::RealTime(now.tv_sec, now.tv_usec * 1000) -
Rosegarden::RealTime(logoShowTime.tv_sec, logoShowTime.tv_usec * 1000);
if (visibleFor < Rosegarden::RealTime(2, 0)) {
int waitTime = visibleFor.sec * 1000 + visibleFor.msec();
QTimer::singleShot(2500 - waitTime, startLogo, SLOT(close()));
} else {
startLogo->close();
}
} else {
// if the start logo is there, it's responsible for showing this;
// otherwise we have to
RG_DEBUG << "main: Showing Tips\n";
KTipDialog::showTip(locate("data", "rosegarden/tips"));
}
config->setGroup(Rosegarden::SequencerOptionsConfigGroup);
// See if the config wants us to load a soundfont
//
if (config->readBoolEntry("sfxloadenabled",false)) {
QString sfxLoadPath = config->readEntry("sfxloadpath", "/bin/sfxload");
QString soundFontPath = config->readEntry("soundfontpath", "");
QFileInfo sfxLoadInfo(sfxLoadPath), soundFontInfo(soundFontPath);
if (sfxLoadInfo.isExecutable() && soundFontInfo.isReadable()) {
KProcess* sfxLoadProcess = new KProcess;
(*sfxLoadProcess) << sfxLoadPath << soundFontPath;
RG_DEBUG << "Starting sfxload : " << sfxLoadPath << " " << soundFontPath << endl;
QObject::connect(sfxLoadProcess, SIGNAL(processExited(KProcess*)),
&app, SLOT(sfxLoadExited(KProcess*)));
sfxLoadProcess->start();
} else {
RG_DEBUG << "sfxload not executable or soundfont not readable : "
<< sfxLoadPath << " " << soundFontPath << endl;
}
} else {
RG_DEBUG << "sfxload disabled\n";
}
#ifdef Q_WS_X11
XSetErrorHandler( _x_errhandler );
#endif
return kapp->exec();
}
|