comparison main/MainWindow.cpp @ 69:76cc2c424268

* Update the main sv.prf for compatibility with Qt 4.2 qmake instead of that from 4.1. Add a README.Qt41 describing how to build with 4.1 if preferred. * Add OSC support for control from external scripts etc (work in progress).
author Chris Cannam
date Fri, 10 Nov 2006 13:27:57 +0000
parents 0229bec2d2dc
children e269ae6ed008
comparison
equal deleted inserted replaced
68:050d764df239 69:76cc2c424268
52 #include "base/PlayParameterRepository.h" 52 #include "base/PlayParameterRepository.h"
53 #include "base/XmlExportable.h" 53 #include "base/XmlExportable.h"
54 #include "base/CommandHistory.h" 54 #include "base/CommandHistory.h"
55 #include "base/Profiler.h" 55 #include "base/Profiler.h"
56 #include "base/Clipboard.h" 56 #include "base/Clipboard.h"
57 #include "osc/OSCQueue.h"
57 58
58 // For version information 59 // For version information
59 #include "vamp/vamp.h" 60 #include "vamp/vamp.h"
60 #include "vamp-sdk/PluginBase.h" 61 #include "vamp-sdk/PluginBase.h"
61 #include "plugin/api/ladspa.h" 62 #include "plugin/api/ladspa.h"
102 m_overview(0), 103 m_overview(0),
103 m_timeRulerLayer(0), 104 m_timeRulerLayer(0),
104 m_audioOutput(withAudioOutput), 105 m_audioOutput(withAudioOutput),
105 m_playSource(0), 106 m_playSource(0),
106 m_playTarget(0), 107 m_playTarget(0),
108 m_oscQueue(new OSCQueue()),
107 m_recentFiles("RecentFiles"), 109 m_recentFiles("RecentFiles"),
108 m_recentTransforms("RecentTransforms", 20), 110 m_recentTransforms("RecentTransforms", 20),
109 m_mainMenusCreated(false), 111 m_mainMenusCreated(false),
110 m_paneMenu(0), 112 m_paneMenu(0),
111 m_layerMenu(0), 113 m_layerMenu(0),
227 connect(Preferences::getInstance(), 229 connect(Preferences::getInstance(),
228 SIGNAL(propertyChanged(PropertyContainer::PropertyName)), 230 SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
229 this, 231 this,
230 SLOT(preferenceChanged(PropertyContainer::PropertyName))); 232 SLOT(preferenceChanged(PropertyContainer::PropertyName)));
231 233
234 if (m_oscQueue->isOK()) {
235 connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC()));
236 QTimer *oscTimer = new QTimer(this);
237 connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC()));
238 oscTimer->start(1000);
239 }
240
232 setupMenus(); 241 setupMenus();
233 setupToolbars(); 242 setupToolbars();
234 243
235 // statusBar()->addWidget(m_descriptionLabel); 244 // statusBar()->addWidget(m_descriptionLabel);
236 245
241 { 250 {
242 closeSession(); 251 closeSession();
243 delete m_playTarget; 252 delete m_playTarget;
244 delete m_playSource; 253 delete m_playSource;
245 delete m_viewManager; 254 delete m_viewManager;
255 delete m_oscQueue;
246 Profiles::getInstance()->dump(); 256 Profiles::getInstance()->dump();
247 } 257 }
248 258
249 void 259 void
250 MainWindow::setupMenus() 260 MainWindow::setupMenus()
1266 tr("Constrain Playback to Selection")); 1276 tr("Constrain Playback to Selection"));
1267 action->setCheckable(true); 1277 action->setCheckable(true);
1268 action->setChecked(m_viewManager->getPlaySelectionMode()); 1278 action->setChecked(m_viewManager->getPlaySelectionMode());
1269 action->setShortcut(tr("s")); 1279 action->setShortcut(tr("s"));
1270 action->setStatusTip(tr("Constrain playback to the selected area")); 1280 action->setStatusTip(tr("Constrain playback to the selected area"));
1281 connect(m_viewManager, SIGNAL(playSelectionModeChanged(bool)),
1282 action, SLOT(setChecked(bool)));
1271 connect(action, SIGNAL(triggered()), this, SLOT(playSelectionToggled())); 1283 connect(action, SIGNAL(triggered()), this, SLOT(playSelectionToggled()));
1272 connect(this, SIGNAL(canPlaySelection(bool)), action, SLOT(setEnabled(bool))); 1284 connect(this, SIGNAL(canPlaySelection(bool)), action, SLOT(setEnabled(bool)));
1273 1285
1274 action = toolbar->addAction(QIcon(":/icons/playloop.png"), 1286 action = toolbar->addAction(QIcon(":/icons/playloop.png"),
1275 tr("Loop Playback")); 1287 tr("Loop Playback"));
1276 action->setCheckable(true); 1288 action->setCheckable(true);
1277 action->setChecked(m_viewManager->getPlayLoopMode()); 1289 action->setChecked(m_viewManager->getPlayLoopMode());
1278 action->setShortcut(tr("l")); 1290 action->setShortcut(tr("l"));
1279 action->setStatusTip(tr("Loop playback")); 1291 action->setStatusTip(tr("Loop playback"));
1292 connect(m_viewManager, SIGNAL(playLoopModeChanged(bool)),
1293 action, SLOT(setChecked(bool)));
1280 connect(action, SIGNAL(triggered()), this, SLOT(playLoopToggled())); 1294 connect(action, SIGNAL(triggered()), this, SLOT(playLoopToggled()));
1281 connect(this, SIGNAL(canPlay(bool)), action, SLOT(setEnabled(bool))); 1295 connect(this, SIGNAL(canPlay(bool)), action, SLOT(setEnabled(bool)));
1282 1296
1283 toolbar = addToolBar(tr("Edit Toolbar")); 1297 toolbar = addToolBar(tr("Edit Toolbar"));
1284 CommandHistory::getInstance()->registerToolbar(toolbar); 1298 CommandHistory::getInstance()->registerToolbar(toolbar);
2857 std::cerr << "WARNING: MainWindow::addPane: unknown action " 2871 std::cerr << "WARNING: MainWindow::addPane: unknown action "
2858 << action->objectName().toStdString() << std::endl; 2872 << action->objectName().toStdString() << std::endl;
2859 return; 2873 return;
2860 } 2874 }
2861 2875
2862 CommandHistory::getInstance()->startCompoundOperation 2876 addPane(i->second, action->text());
2863 (action->text(), true); 2877 }
2878
2879 void
2880 MainWindow::addPane(const PaneConfiguration &configuration, QString text)
2881 {
2882 CommandHistory::getInstance()->startCompoundOperation(text, true);
2864 2883
2865 AddPaneCommand *command = new AddPaneCommand(this); 2884 AddPaneCommand *command = new AddPaneCommand(this);
2866 CommandHistory::getInstance()->addCommand(command); 2885 CommandHistory::getInstance()->addCommand(command);
2867 2886
2868 Pane *pane = command->getPane(); 2887 Pane *pane = command->getPane();
2869 2888
2870 if (i->second.layer == LayerFactory::Spectrum) { 2889 if (configuration.layer == LayerFactory::Spectrum) {
2871 pane->setPlaybackFollow(View::PlaybackScrollContinuous); 2890 pane->setPlaybackFollow(View::PlaybackScrollContinuous);
2872 } 2891 }
2873 2892
2874 if (i->second.layer != LayerFactory::TimeRuler && 2893 if (configuration.layer != LayerFactory::TimeRuler &&
2875 i->second.layer != LayerFactory::Spectrum) { 2894 configuration.layer != LayerFactory::Spectrum) {
2876 2895
2877 if (!m_timeRulerLayer) { 2896 if (!m_timeRulerLayer) {
2878 // std::cerr << "no time ruler layer, creating one" << std::endl; 2897 // std::cerr << "no time ruler layer, creating one" << std::endl;
2879 m_timeRulerLayer = m_document->createMainModelLayer 2898 m_timeRulerLayer = m_document->createMainModelLayer
2880 (LayerFactory::TimeRuler); 2899 (LayerFactory::TimeRuler);
2883 // std::cerr << "adding time ruler layer " << m_timeRulerLayer << std::endl; 2902 // std::cerr << "adding time ruler layer " << m_timeRulerLayer << std::endl;
2884 2903
2885 m_document->addLayerToView(pane, m_timeRulerLayer); 2904 m_document->addLayerToView(pane, m_timeRulerLayer);
2886 } 2905 }
2887 2906
2888 Layer *newLayer = m_document->createLayer(i->second.layer); 2907 Layer *newLayer = m_document->createLayer(configuration.layer);
2889 2908
2890 Model *suggestedModel = i->second.sourceModel; 2909 Model *suggestedModel = configuration.sourceModel;
2891 Model *model = 0; 2910 Model *model = 0;
2892 2911
2893 if (suggestedModel) { 2912 if (suggestedModel) {
2894 2913
2895 // check its validity 2914 // check its validity
2910 2929
2911 if (!model) model = m_document->getMainModel(); 2930 if (!model) model = m_document->getMainModel();
2912 2931
2913 m_document->setModel(newLayer, model); 2932 m_document->setModel(newLayer, model);
2914 2933
2915 m_document->setChannel(newLayer, i->second.channel); 2934 m_document->setChannel(newLayer, configuration.channel);
2916 m_document->addLayerToView(pane, newLayer); 2935 m_document->addLayerToView(pane, newLayer);
2917 2936
2918 m_paneStack->setCurrentPane(pane); 2937 m_paneStack->setCurrentPane(pane);
2919 2938
2920 CommandHistory::getInstance()->endCompoundOperation(); 2939 CommandHistory::getInstance()->endCompoundOperation();
3386 QTreeView *view = new QTreeView(); 3405 QTreeView *view = new QTreeView();
3387 LayerTreeModel *tree = new LayerTreeModel(m_paneStack); 3406 LayerTreeModel *tree = new LayerTreeModel(m_paneStack);
3388 view->expand(tree->index(0, 0, QModelIndex())); 3407 view->expand(tree->index(0, 0, QModelIndex()));
3389 view->setModel(tree); 3408 view->setModel(tree);
3390 view->show(); 3409 view->show();
3410 }
3411
3412 void
3413 MainWindow::pollOSC()
3414 {
3415 if (m_oscQueue->isEmpty()) return;
3416 std::cerr << "MainWindow::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl;
3417
3418 OSCMessage message = m_oscQueue->readMessage();
3419
3420 if (message.getTarget() != 0) {
3421 return; //!!! for now -- this class is target 0, others not handled yet
3422 }
3423
3424 handleOSCMessage(message);
3425 }
3426
3427 void
3428 MainWindow::handleOSCMessage(const OSCMessage &message)
3429 {
3430 // This large function should really be abstracted out.
3431
3432 if (message.getMethod() == "open") {
3433
3434 if (message.getArgCount() == 1 &&
3435 message.getArg(0).canConvert(QVariant::String)) {
3436 QString path = message.getArg(0).toString();
3437 if (!openSomeFile(path, ReplaceMainModel)) {
3438 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
3439 << path.toStdString() << "\"" << std::endl;
3440 }
3441 //!!! we really need to spin here and not return until the
3442 // file has been completely decoded...
3443 }
3444
3445 } else if (message.getMethod() == "openadditional") {
3446
3447 if (message.getArgCount() == 1 &&
3448 message.getArg(0).canConvert(QVariant::String)) {
3449 QString path = message.getArg(0).toString();
3450 if (!openSomeFile(path, CreateAdditionalModel)) {
3451 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
3452 << path.toStdString() << "\"" << std::endl;
3453 }
3454 }
3455
3456 } else if (message.getMethod() == "recent" ||
3457 message.getMethod() == "last") {
3458
3459 int n = 0;
3460 if (message.getMethod() == "recent" &&
3461 message.getArgCount() == 1 &&
3462 message.getArg(0).canConvert(QVariant::Int)) {
3463 n = message.getArg(0).toInt() - 1;
3464 }
3465 std::vector<QString> recent = m_recentFiles.getRecent();
3466 if (n >= 0 && n < recent.size()) {
3467 if (!openSomeFile(recent[n], ReplaceMainModel)) {
3468 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
3469 << recent[n].toStdString() << "\"" << std::endl;
3470 }
3471 }
3472
3473 } else if (message.getMethod() == "save") {
3474
3475 QString path;
3476 if (message.getArgCount() == 1 &&
3477 message.getArg(0).canConvert(QVariant::String)) {
3478 path = message.getArg(0).toString();
3479 if (QFileInfo(path).exists()) {
3480 std::cerr << "MainWindow::handleOSCMessage: Refusing to overwrite existing file in save" << std::endl;
3481 } else {
3482 saveSessionFile(path);
3483 }
3484 }
3485
3486 } else if (message.getMethod() == "export") {
3487
3488 QString path;
3489 if (getMainModel()) {
3490 if (message.getArgCount() == 1 &&
3491 message.getArg(0).canConvert(QVariant::String)) {
3492 path = message.getArg(0).toString();
3493 if (QFileInfo(path).exists()) {
3494 std::cerr << "MainWindow::handleOSCMessage: Refusing to overwrite existing file in export" << std::endl;
3495 } else {
3496 WavFileWriter writer(path,
3497 getMainModel()->getSampleRate(),
3498 getMainModel()->getChannelCount());
3499 MultiSelection ms = m_viewManager->getSelection();
3500 if (!ms.getSelections().empty()) {
3501 writer.writeModel(getMainModel(), &ms);
3502 } else {
3503 writer.writeModel(getMainModel());
3504 }
3505 }
3506 }
3507 }
3508
3509 } else if (message.getMethod() == "jump" ||
3510 message.getMethod() == "play") {
3511
3512 if (getMainModel()) {
3513
3514 unsigned long frame = m_viewManager->getPlaybackFrame();
3515 bool selection = false;
3516 bool play = (message.getMethod() == "play");
3517
3518 if (message.getArgCount() == 1) {
3519
3520 if (message.getArg(0).canConvert(QVariant::String) &&
3521 message.getArg(0).toString() == "selection") {
3522
3523 selection = true;
3524
3525 } else if (message.getArg(0).canConvert(QVariant::String) &&
3526 message.getArg(0).toString() == "end") {
3527
3528 frame = getMainModel()->getEndFrame();
3529
3530 } else if (message.getArg(0).canConvert(QVariant::Double)) {
3531
3532 double time = message.getArg(0).toDouble();
3533 if (time < 0.0) time = 0.0;
3534
3535 frame = lrint(time * getMainModel()->getSampleRate());
3536 }
3537 }
3538
3539 if (frame > getMainModel()->getEndFrame()) {
3540 frame = getMainModel()->getEndFrame();
3541 }
3542
3543 if (play) {
3544 m_viewManager->setPlaySelectionMode(selection);
3545 }
3546
3547 if (selection) {
3548 MultiSelection::SelectionList sl = m_viewManager->getSelections();
3549 if (!sl.empty()) {
3550 frame = sl.begin()->getStartFrame();
3551 }
3552 }
3553
3554 m_viewManager->setPlaybackFrame(frame);
3555
3556 if (play && !m_playSource->isPlaying()) {
3557 m_playSource->play(frame);
3558 }
3559 }
3560
3561 } else if (message.getMethod() == "stop") {
3562
3563 if (m_playSource->isPlaying()) m_playSource->stop();
3564
3565 } else if (message.getMethod() == "loop") {
3566
3567 if (message.getArgCount() == 1 &&
3568 message.getArg(0).canConvert(QVariant::String)) {
3569
3570 QString str = message.getArg(0).toString();
3571 if (str == "on") {
3572 m_viewManager->setPlayLoopMode(true);
3573 } else if (str == "off") {
3574 m_viewManager->setPlayLoopMode(false);
3575 }
3576 }
3577
3578 } else if (message.getMethod() == "select" ||
3579 message.getMethod() == "addselect") {
3580
3581 if (getMainModel()) {
3582
3583 unsigned long f0 = getMainModel()->getStartFrame();
3584 unsigned long f1 = getMainModel()->getEndFrame();
3585
3586 bool done = false;
3587
3588 if (message.getArgCount() == 2 &&
3589 message.getArg(0).canConvert(QVariant::Double) &&
3590 message.getArg(1).canConvert(QVariant::Double)) {
3591
3592 double t0 = message.getArg(0).toDouble();
3593 double t1 = message.getArg(1).toDouble();
3594 if (t1 < t0) { double temp = t0; t0 = t1; t1 = temp; }
3595 if (t0 < 0.0) t0 = 0.0;
3596 if (t1 < 0.0) t1 = 0.0;
3597
3598 f0 = lrint(t0 * getMainModel()->getSampleRate());
3599 f1 = lrint(t1 * getMainModel()->getSampleRate());
3600
3601 } else if (message.getArgCount() == 1 &&
3602 message.getArg(0).canConvert(QVariant::String)) {
3603
3604 QString str = message.getArg(0).toString();
3605 if (str == "none") {
3606 m_viewManager->clearSelections();
3607 done = true;
3608 }
3609 }
3610
3611 if (!done) {
3612 if (message.getMethod() == "select") {
3613 m_viewManager->setSelection(Selection(f0, f1));
3614 } else {
3615 m_viewManager->addSelection(Selection(f0, f1));
3616 }
3617 }
3618 }
3619
3620 } else if (message.getMethod() == "add") {
3621
3622 if (getMainModel()) {
3623
3624 if (message.getArgCount() >= 1 &&
3625 message.getArg(0).canConvert(QVariant::String)) {
3626
3627 int channel = -1;
3628 if (message.getArgCount() == 2 &&
3629 message.getArg(0).canConvert(QVariant::Int)) {
3630 channel = message.getArg(0).toInt();
3631 if (channel < -1 ||
3632 channel > getMainModel()->getChannelCount()) {
3633 std::cerr << "WARNING: MainWindow::handleOSCMessage: channel "
3634 << channel << " out of range" << std::endl;
3635 channel = -1;
3636 }
3637 }
3638
3639 QString str = message.getArg(0).toString();
3640
3641 LayerFactory::LayerType type =
3642 LayerFactory::getInstance()->getLayerTypeForName(str);
3643
3644 if (type == LayerFactory::UnknownLayer) {
3645 std::cerr << "WARNING: MainWindow::handleOSCMessage: unknown layer "
3646 << "type " << str.toStdString() << std::endl;
3647 } else {
3648
3649 PaneConfiguration configuration(type,
3650 getMainModel(),
3651 channel);
3652
3653 addPane(configuration,
3654 tr("Add %1 Pane")
3655 .arg(LayerFactory::getInstance()->
3656 getLayerPresentationName(type)));
3657 }
3658 }
3659 }
3660
3661 } else if (message.getMethod() == "undo") {
3662
3663 CommandHistory::getInstance()->undo();
3664
3665 } else if (message.getMethod() == "redo") {
3666
3667 CommandHistory::getInstance()->redo();
3668
3669 } else if (message.getMethod() == "set") {
3670
3671 if (message.getArgCount() >= 2 &&
3672 message.getArg(0).canConvert(QVariant::String) &&
3673 message.getArg(1).canConvert(QVariant::Double)) {
3674
3675 QString property = message.getArg(0).toString();
3676 float value = (float)message.getArg(1).toDouble();
3677
3678 if (property == "gain") {
3679 if (value < 0.0) value = 0.0;
3680 m_fader->setValue(value);
3681 if (m_playTarget) m_playTarget->setOutputGain(value);
3682 } else if (property == "speedup") {
3683 m_playSpeed->setMappedValue(value);
3684 } else if (property == "overlays") {
3685 if (value < 0.5) {
3686 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
3687 } else if (value < 1.5) {
3688 m_viewManager->setOverlayMode(ViewManager::BasicOverlays);
3689 } else {
3690 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
3691 }
3692 }
3693 }
3694
3695 } else if (message.getMethod() == "setcurrent") {
3696
3697 int paneIndex = -1, layerIndex = -1;
3698 bool wantLayer = false;
3699
3700 if (message.getArgCount() >= 1 &&
3701 message.getArg(0).canConvert(QVariant::Int)) {
3702
3703 paneIndex = message.getArg(0).toInt() - 1;
3704
3705 if (message.getArgCount() >= 2 &&
3706 message.getArg(1).canConvert(QVariant::Int)) {
3707 wantLayer = true;
3708 layerIndex = message.getArg(1).toInt() - 1;
3709 }
3710 }
3711
3712 if (paneIndex >= 0 && paneIndex < m_paneStack->getPaneCount()) {
3713 Pane *pane = m_paneStack->getPane(paneIndex);
3714 if (layerIndex >= 0 && layerIndex < pane->getLayerCount()) {
3715 Layer *layer = pane->getLayer(layerIndex);
3716 m_paneStack->setCurrentLayer(pane, layer);
3717 } else if (wantLayer && layerIndex == -1) {
3718 m_paneStack->setCurrentLayer(pane, 0);
3719 } else {
3720 m_paneStack->setCurrentPane(pane);
3721 }
3722 }
3723
3724 } else if (message.getMethod() == "delete") {
3725
3726 if (message.getArgCount() == 1 &&
3727 message.getArg(0).canConvert(QVariant::String)) {
3728
3729 QString target = message.getArg(0).toString();
3730
3731 if (target == "pane") {
3732
3733 deleteCurrentPane();
3734
3735 } else if (target == "layer") {
3736
3737 deleteCurrentLayer();
3738
3739 } else {
3740
3741 std::cerr << "WARNING: MainWindow::handleOSCMessage: Unknown delete target " << target.toStdString() << std::endl;
3742 }
3743 }
3744
3745 } else if (message.getMethod() == "zoom") {
3746
3747 if (message.getArgCount() == 1) {
3748 if (message.getArg(0).canConvert(QVariant::String) &&
3749 message.getArg(0).toString() == "in") {
3750 zoomIn();
3751 } else if (message.getArg(0).canConvert(QVariant::String) &&
3752 message.getArg(0).toString() == "out") {
3753 zoomOut();
3754 } else if (message.getArg(0).canConvert(QVariant::String) &&
3755 message.getArg(0).toString() == "default") {
3756 zoomDefault();
3757 } else if (message.getArg(0).canConvert(QVariant::Double)) {
3758 double level = message.getArg(0).toDouble();
3759 Pane *currentPane = m_paneStack->getCurrentPane();
3760 if (level < 1.0) level = 1.0;
3761 if (currentPane) currentPane->setZoomLevel(lrint(level));
3762 }
3763 }
3764
3765 } else {
3766 std::cerr << "WARNING: MainWindow::handleOSCMessage: Unknown or unsupported "
3767 << "method \"" << message.getMethod().toStdString()
3768 << "\"" << std::endl;
3769 }
3770
3391 } 3771 }
3392 3772
3393 void 3773 void
3394 MainWindow::preferenceChanged(PropertyContainer::PropertyName name) 3774 MainWindow::preferenceChanged(PropertyContainer::PropertyName name)
3395 { 3775 {
3535 #ifdef HAVE_VAMP 3915 #ifdef HAVE_VAMP
3536 aboutText += tr("<br>With Vamp plugin support (API v%1, SDK v%2) &copy; Chris Cannam").arg(VAMP_API_VERSION).arg(VAMP_SDK_VERSION); 3916 aboutText += tr("<br>With Vamp plugin support (API v%1, SDK v%2) &copy; Chris Cannam").arg(VAMP_API_VERSION).arg(VAMP_SDK_VERSION);
3537 #endif 3917 #endif
3538 aboutText += tr("<br>With LADSPA plugin support (API v%1) &copy; Richard Furse, Paul Davis, Stefan Westerfeld").arg(LADSPA_VERSION); 3918 aboutText += tr("<br>With LADSPA plugin support (API v%1) &copy; Richard Furse, Paul Davis, Stefan Westerfeld").arg(LADSPA_VERSION);
3539 aboutText += tr("<br>With DSSI plugin support (API v%1) &copy; Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION); 3919 aboutText += tr("<br>With DSSI plugin support (API v%1) &copy; Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION);
3920 #ifdef HAVE_LIBLO
3921 aboutText += tr("<br>With liblo Lite OSC library (v%1) &copy; Steve Harris").arg(LIBLO_VERSION);
3922 if (m_oscQueue->isOK()) {
3923 aboutText += tr("<p>The OSC URL for this instance is: \"%1\"").arg(m_oscQueue->getOSCURL());
3924 }
3925 #endif
3540 aboutText += "</p>"; 3926 aboutText += "</p>";
3541 #endif 3927 #endif
3542 3928
3543 aboutText += 3929 aboutText +=
3544 "<p>Sonic Visualiser Copyright &copy; 2005 - 2006 Chris Cannam<br>" 3930 "<p>Sonic Visualiser Copyright &copy; 2005 - 2006 Chris Cannam<br>"