From 145364a8af6a1fec06556221e66d4b724a62fc9a Mon Sep 17 00:00:00 2001 From: tpearson Date: Mon, 1 Mar 2010 18:37:05 +0000 Subject: Added old abandoned KDE3 version of the RoseGarden MIDI tool git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/rosegarden@1097595 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- src/gui/studio/AudioMixerWindow.cpp | 1734 ++++++++++++++++++++++++++ src/gui/studio/AudioMixerWindow.h | 191 +++ src/gui/studio/AudioPlugin.cpp | 78 ++ src/gui/studio/AudioPlugin.h | 117 ++ src/gui/studio/AudioPluginClipboard.cpp | 32 + src/gui/studio/AudioPluginClipboard.h | 52 + src/gui/studio/AudioPluginManager.cpp | 307 +++++ src/gui/studio/AudioPluginManager.h | 118 ++ src/gui/studio/AudioPluginOSCGUI.cpp | 234 ++++ src/gui/studio/AudioPluginOSCGUI.h | 77 ++ src/gui/studio/AudioPluginOSCGUIManager.cpp | 711 +++++++++++ src/gui/studio/AudioPluginOSCGUIManager.h | 104 ++ src/gui/studio/BankEditorDialog.cpp | 1713 +++++++++++++++++++++++++ src/gui/studio/BankEditorDialog.h | 211 ++++ src/gui/studio/ChangeRecordDeviceCommand.cpp | 66 + src/gui/studio/ChangeRecordDeviceCommand.h | 54 + src/gui/studio/DeviceEditorDialog.cpp | 406 ++++++ src/gui/studio/DeviceEditorDialog.h | 87 ++ src/gui/studio/DeviceManagerDialog.cpp | 833 +++++++++++++ src/gui/studio/DeviceManagerDialog.h | 121 ++ src/gui/studio/MidiBankListViewItem.cpp | 98 ++ src/gui/studio/MidiBankListViewItem.h | 70 ++ src/gui/studio/MidiDeviceListViewItem.cpp | 88 ++ src/gui/studio/MidiDeviceListViewItem.h | 69 + src/gui/studio/MidiKeyMapListViewItem.cpp | 56 + src/gui/studio/MidiKeyMapListViewItem.h | 59 + src/gui/studio/MidiKeyMappingEditor.cpp | 197 +++ src/gui/studio/MidiKeyMappingEditor.h | 78 ++ src/gui/studio/MidiMixerVUMeter.cpp | 53 + src/gui/studio/MidiMixerVUMeter.h | 61 + src/gui/studio/MidiMixerWindow.cpp | 742 +++++++++++ src/gui/studio/MidiMixerWindow.h | 125 ++ src/gui/studio/MidiProgramsEditor.cpp | 631 ++++++++++ src/gui/studio/MidiProgramsEditor.h | 119 ++ src/gui/studio/MixerWindow.cpp | 75 ++ src/gui/studio/MixerWindow.h | 77 ++ src/gui/studio/NameSetEditor.cpp | 190 +++ src/gui/studio/NameSetEditor.h | 90 ++ src/gui/studio/OSCMessage.cpp | 87 ++ src/gui/studio/OSCMessage.h | 75 ++ src/gui/studio/RemapInstrumentDialog.cpp | 184 +++ src/gui/studio/RemapInstrumentDialog.h | 84 ++ src/gui/studio/StudioControl.cpp | 582 +++++++++ src/gui/studio/StudioControl.h | 152 +++ src/gui/studio/SynthPluginManagerDialog.cpp | 360 ++++++ src/gui/studio/SynthPluginManagerDialog.h | 98 ++ src/gui/studio/TimerCallbackAssistant.cpp | 57 + src/gui/studio/TimerCallbackAssistant.h | 61 + 48 files changed, 11864 insertions(+) create mode 100644 src/gui/studio/AudioMixerWindow.cpp create mode 100644 src/gui/studio/AudioMixerWindow.h create mode 100644 src/gui/studio/AudioPlugin.cpp create mode 100644 src/gui/studio/AudioPlugin.h create mode 100644 src/gui/studio/AudioPluginClipboard.cpp create mode 100644 src/gui/studio/AudioPluginClipboard.h create mode 100644 src/gui/studio/AudioPluginManager.cpp create mode 100644 src/gui/studio/AudioPluginManager.h create mode 100644 src/gui/studio/AudioPluginOSCGUI.cpp create mode 100644 src/gui/studio/AudioPluginOSCGUI.h create mode 100644 src/gui/studio/AudioPluginOSCGUIManager.cpp create mode 100644 src/gui/studio/AudioPluginOSCGUIManager.h create mode 100644 src/gui/studio/BankEditorDialog.cpp create mode 100644 src/gui/studio/BankEditorDialog.h create mode 100644 src/gui/studio/ChangeRecordDeviceCommand.cpp create mode 100644 src/gui/studio/ChangeRecordDeviceCommand.h create mode 100644 src/gui/studio/DeviceEditorDialog.cpp create mode 100644 src/gui/studio/DeviceEditorDialog.h create mode 100644 src/gui/studio/DeviceManagerDialog.cpp create mode 100644 src/gui/studio/DeviceManagerDialog.h create mode 100644 src/gui/studio/MidiBankListViewItem.cpp create mode 100644 src/gui/studio/MidiBankListViewItem.h create mode 100644 src/gui/studio/MidiDeviceListViewItem.cpp create mode 100644 src/gui/studio/MidiDeviceListViewItem.h create mode 100644 src/gui/studio/MidiKeyMapListViewItem.cpp create mode 100644 src/gui/studio/MidiKeyMapListViewItem.h create mode 100644 src/gui/studio/MidiKeyMappingEditor.cpp create mode 100644 src/gui/studio/MidiKeyMappingEditor.h create mode 100644 src/gui/studio/MidiMixerVUMeter.cpp create mode 100644 src/gui/studio/MidiMixerVUMeter.h create mode 100644 src/gui/studio/MidiMixerWindow.cpp create mode 100644 src/gui/studio/MidiMixerWindow.h create mode 100644 src/gui/studio/MidiProgramsEditor.cpp create mode 100644 src/gui/studio/MidiProgramsEditor.h create mode 100644 src/gui/studio/MixerWindow.cpp create mode 100644 src/gui/studio/MixerWindow.h create mode 100644 src/gui/studio/NameSetEditor.cpp create mode 100644 src/gui/studio/NameSetEditor.h create mode 100644 src/gui/studio/OSCMessage.cpp create mode 100644 src/gui/studio/OSCMessage.h create mode 100644 src/gui/studio/RemapInstrumentDialog.cpp create mode 100644 src/gui/studio/RemapInstrumentDialog.h create mode 100644 src/gui/studio/StudioControl.cpp create mode 100644 src/gui/studio/StudioControl.h create mode 100644 src/gui/studio/SynthPluginManagerDialog.cpp create mode 100644 src/gui/studio/SynthPluginManagerDialog.h create mode 100644 src/gui/studio/TimerCallbackAssistant.cpp create mode 100644 src/gui/studio/TimerCallbackAssistant.h (limited to 'src/gui/studio') diff --git a/src/gui/studio/AudioMixerWindow.cpp b/src/gui/studio/AudioMixerWindow.cpp new file mode 100644 index 0000000..e8d09b3 --- /dev/null +++ b/src/gui/studio/AudioMixerWindow.cpp @@ -0,0 +1,1734 @@ +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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 "AudioMixerWindow.h" +#include +#include + +#include "AudioPlugin.h" +#include "AudioPluginManager.h" +#include "MixerWindow.h" +#include "StudioControl.h" +#include "sound/Midi.h" +#include "misc/Debug.h" +#include "gui/application/RosegardenDCOP.h" +#include "base/AudioLevel.h" +#include "base/AudioPluginInstance.h" +#include "base/Composition.h" +#include "base/Device.h" +#include "base/Instrument.h" +#include "base/MidiProgram.h" +#include "base/Studio.h" +#include "document/RosegardenGUIDoc.h" +#include "gui/editors/notation/NotePixmapFactory.h" +#include "gui/general/GUIPalette.h" +#include "gui/seqmanager/SequencerMapper.h" +#include "gui/seqmanager/SequenceManager.h" +#include "gui/widgets/AudioRouteMenu.h" +#include "gui/widgets/AudioVUMeter.h" +#include "gui/widgets/Fader.h" +#include "gui/widgets/Rotary.h" +#include "gui/widgets/VUMeter.h" +#include "sound/MappedCommon.h" +#include "sound/MappedEvent.h" +#include "sound/MappedStudio.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace Rosegarden +{ + +// We define these such that the default of no-bits-set for the +// studio's mixer display options produces the most sensible result +static const unsigned int MIXER_OMIT_FADERS = 1 << 0; +static const unsigned int MIXER_OMIT_SUBMASTERS = 1 << 1; +static const unsigned int MIXER_OMIT_PLUGINS = 1 << 2; +static const unsigned int MIXER_SHOW_UNASSIGNED_FADERS = 1 << 3; +static const unsigned int MIXER_OMIT_SYNTH_FADERS = 1 << 4; + + +AudioMixerWindow::AudioMixerWindow(QWidget *parent, + RosegardenGUIDoc *document): + MixerWindow(parent, document), + m_mainBox (0) +{ + populate(); + + KStdAction::close(this, + SLOT(slotClose()), + actionCollection()); + + QIconSet icon = QIconSet(NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap + ("transport-play"))); + KAction *play = new KAction(i18n("&Play"), icon, Key_Enter, this, + SIGNAL(play()), actionCollection(), "play"); + // Alternative shortcut for Play + KShortcut playShortcut = play->shortcut(); + playShortcut.append( KKey(Key_Return + CTRL) ); + play->setShortcut(playShortcut); + + icon = QIconSet(NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap + ("transport-stop"))); + new KAction(i18n("&Stop"), icon, Key_Insert, this, + SIGNAL(stop()), actionCollection(), "stop"); + + icon = QIconSet(NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap + ("transport-rewind"))); + new KAction(i18n("Re&wind"), icon, Key_End, this, + SIGNAL(rewindPlayback()), actionCollection(), + "playback_pointer_back_bar"); + + icon = QIconSet(NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap + ("transport-ffwd"))); + new KAction(i18n("&Fast Forward"), icon, Key_PageDown, this, + SIGNAL(fastForwardPlayback()), actionCollection(), + "playback_pointer_forward_bar"); + + icon = QIconSet(NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap + ("transport-rewind-end"))); + new KAction(i18n("Rewind to &Beginning"), icon, 0, this, + SIGNAL(rewindPlaybackToBeginning()), actionCollection(), + "playback_pointer_start"); + + icon = QIconSet(NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap + ("transport-ffwd-end"))); + new KAction(i18n("Fast Forward to &End"), icon, 0, this, + SIGNAL(fastForwardPlaybackToEnd()), actionCollection(), + "playback_pointer_end"); + + icon = QIconSet(NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap + ("transport-record"))); + new KAction(i18n("&Record"), icon, 0, this, + SIGNAL(record()), actionCollection(), + "record"); + + icon = QIconSet(NotePixmapFactory::toQPixmap(NotePixmapFactory::makeToolbarPixmap + ("transport-panic"))); + new KAction(i18n("Panic"), icon, Key_P + CTRL + ALT, this, + SIGNAL(panic()), actionCollection(), + "panic"); + + unsigned int mixerOptions = m_studio->getMixerDisplayOptions(); + + (new KToggleAction(i18n("Show Audio &Faders"), 0, this, + SLOT(slotToggleFaders()), actionCollection(), + "show_audio_faders"))->setChecked + (!(mixerOptions & MIXER_OMIT_FADERS)); + + (new KToggleAction(i18n("Show Synth &Faders"), 0, this, + SLOT(slotToggleSynthFaders()), actionCollection(), + "show_synth_faders"))->setChecked + (!(mixerOptions & MIXER_OMIT_SYNTH_FADERS)); + + (new KToggleAction(i18n("Show &Submasters"), 0, this, + SLOT(slotToggleSubmasters()), actionCollection(), + "show_audio_submasters"))->setChecked + (!(mixerOptions & MIXER_OMIT_SUBMASTERS)); + + (new KToggleAction(i18n("Show &Plugin Buttons"), 0, this, + SLOT(slotTogglePluginButtons()), actionCollection(), + "show_plugin_buttons"))->setChecked + (!(mixerOptions & MIXER_OMIT_PLUGINS)); + + (new KToggleAction(i18n("Show &Unassigned Faders"), 0, this, + SLOT(slotToggleUnassignedFaders()), actionCollection(), + "show_unassigned_faders"))->setChecked + (mixerOptions & MIXER_SHOW_UNASSIGNED_FADERS); + + KRadioAction *action = 0; + + for (int i = 1; i <= 16; i *= 2) { + action = + new KRadioAction(i18n("1 Input", "%n Inputs", i), + 0, this, + SLOT(slotSetInputCountFromAction()), actionCollection(), + QString("inputs_%1").arg(i)); + action->setExclusiveGroup("inputs"); + if (i == int(m_studio->getRecordIns().size())) + action->setChecked(true); + } + + action = new KRadioAction + (i18n("No Submasters"), + 0, this, + SLOT(slotSetSubmasterCountFromAction()), actionCollection(), + QString("submasters_0")); + action->setExclusiveGroup("submasters"); + action->setChecked(true); + + for (int i = 2; i <= 8; i *= 2) { + action = new KRadioAction + (i18n("1 Submaster", "%n Submasters", i), + 0, this, + SLOT(slotSetSubmasterCountFromAction()), actionCollection(), + QString("submasters_%1").arg(i)); + action->setExclusiveGroup("submasters"); + if (i == int(m_studio->getBusses().size()) - 1) + action->setChecked(true); + } + + createGUI("mixer.rc"); +} + +AudioMixerWindow::~AudioMixerWindow() +{ + RG_DEBUG << "AudioMixerWindow::~AudioMixerWindow\n"; + depopulate(); +} + +void +AudioMixerWindow::depopulate() +{ + if (!m_mainBox) + return ; + + // All the widgets will be deleted when the main box goes, + // except that we need to delete the AudioRouteMenus first + // because they aren't actually widgets but do contain them + + for (FaderMap::iterator i = m_faders.begin(); + i != m_faders.end(); ++i) { + delete i->second.m_input; + delete i->second.m_output; + } + + m_faders.clear(); + m_submasters.clear(); + + delete m_mainBox; + m_mainBox = 0; +} + +void +AudioMixerWindow::populate() +{ + if (m_mainBox) { + + depopulate(); + + } else { + + m_surroundBox = new QHBox(this); + setCentralWidget(m_surroundBox); + } + + QFont font; + font.setPointSize(font.pointSize() * 8 / 10); + font.setBold(false); + setFont(font); + + QFont boldFont(font); + boldFont.setBold(true); + + m_mainBox = new QFrame(m_surroundBox); + + InstrumentList instruments = m_studio->getPresentationInstruments(); + BussList busses = m_studio->getBusses(); + + QString pixmapDir = KGlobal::dirs()->findResource("appdata", "pixmaps/"); + m_monoPixmap.load(QString("%1/misc/mono.xpm").arg(pixmapDir)); + m_stereoPixmap.load(QString("%1/misc/stereo.xpm").arg(pixmapDir)); + + // Total cols: is 2 for each fader, submaster or master, plus 1 + // for each spacer. + QGridLayout *mainLayout = new QGridLayout + (m_mainBox, (instruments.size() + busses.size()) * 3, 7); + + setCaption(i18n("Audio Mixer")); + + int count = 1; + int col = 0; + + unsigned int mixerOptions = m_studio->getMixerDisplayOptions(); + + bool showUnassigned = (mixerOptions & MIXER_SHOW_UNASSIGNED_FADERS); + + for (InstrumentList::iterator i = instruments.begin(); + i != instruments.end(); ++i) { + + if ((*i)->getType() != Instrument::Audio && + (*i)->getType() != Instrument::SoftSynth) + continue; + + FaderRec rec; + + if (!showUnassigned) { + // Do any tracks use this instrument? + if (!isInstrumentAssigned((*i)->getId())) { + continue; + } + } + rec.m_populated = true; + + if ((*i)->getType() == Instrument::Audio) { + rec.m_input = new AudioRouteMenu(m_mainBox, + AudioRouteMenu::In, + AudioRouteMenu::Compact, + m_studio, *i); + QToolTip::add + (rec.m_input->getWidget(), i18n("Record input source")); + rec.m_input->getWidget()->setMaximumWidth(45); + } else { + rec.m_input = 0; + } + + rec.m_output = new AudioRouteMenu(m_mainBox, + AudioRouteMenu::Out, + AudioRouteMenu::Compact, + m_studio, *i); + QToolTip::add + (rec.m_output->getWidget(), i18n("Output destination")); + rec.m_output->getWidget()->setMaximumWidth(45); + + rec.m_pan = new Rotary + (m_mainBox, -100.0, 100.0, 1.0, 5.0, 0.0, 20, + Rotary::NoTicks, false, true); + + if ((*i)->getType() == Instrument::Audio) { + rec.m_pan->setKnobColour(GUIPalette::getColour(GUIPalette::RotaryPastelGreen)); + } else { + rec.m_pan->setKnobColour(GUIPalette::getColour(GUIPalette::RotaryPastelYellow)); + } + + QToolTip::add + (rec.m_pan, i18n("Pan")); + + rec.m_fader = new Fader + (AudioLevel::LongFader, 20, 240, m_mainBox); + rec.m_meter = new AudioVUMeter + (m_mainBox, VUMeter::AudioPeakHoldIECLong, true, rec.m_input != 0, + 20, 240); + + QToolTip::add + (rec.m_fader, i18n("Audio level")); + QToolTip::add + (rec.m_meter, i18n("Audio level")); + + rec.m_stereoButton = new QPushButton(m_mainBox); + rec.m_stereoButton->setPixmap(m_monoPixmap); + rec.m_stereoButton->setFixedSize(20, 20); + rec.m_stereoButton->setFlat(true); + rec.m_stereoness = false; + QToolTip::add + (rec.m_stereoButton, i18n("Mono or stereo")); + + rec.m_muteButton = new QPushButton(m_mainBox); + rec.m_muteButton->setText("M"); + rec.m_muteButton->setToggleButton(true); + rec.m_muteButton->setFixedWidth(rec.m_stereoButton->width()); + rec.m_muteButton->setFixedHeight(rec.m_stereoButton->height()); + rec.m_muteButton->setFlat(true); + QToolTip::add + (rec.m_muteButton, i18n("Mute")); + + rec.m_soloButton = new QPushButton(m_mainBox); + rec.m_soloButton->setText("S"); + rec.m_soloButton->setToggleButton(true); + rec.m_soloButton->setFixedWidth(rec.m_stereoButton->width()); + rec.m_soloButton->setFixedHeight(rec.m_stereoButton->height()); + rec.m_soloButton->setFlat(true); + QToolTip::add + (rec.m_soloButton, i18n("Solo")); + + rec.m_recordButton = new QPushButton(m_mainBox); + rec.m_recordButton->setText("R"); + rec.m_recordButton->setToggleButton(true); + rec.m_recordButton->setFixedWidth(rec.m_stereoButton->width()); + rec.m_recordButton->setFixedHeight(rec.m_stereoButton->height()); + rec.m_recordButton->setFlat(true); + QToolTip::add + (rec.m_recordButton, i18n("Arm recording")); + + rec.m_pluginBox = new QVBox(m_mainBox); + + for (int p = 0; p < 5; ++p) { + QPushButton *plugin = new QPushButton(rec.m_pluginBox, "pluginButton"); + plugin->setText(i18n("")); + plugin->setMaximumWidth(45); + QToolTip::add + (plugin, i18n("Audio plugin button")); + rec.m_plugins.push_back(plugin); + connect(plugin, SIGNAL(clicked()), + this, SLOT(slotSelectPlugin())); + } + + QLabel *idLabel; + QString idString; + if ((*i)->getType() == Instrument::Audio) { + idString = i18n("Audio %1").arg((*i)->getId() - + AudioInstrumentBase + 1); + idLabel = new QLabel(idString, m_mainBox, "audioIdLabel"); + } else { + idString = i18n("Synth %1").arg((*i)->getId() - + SoftSynthInstrumentBase + 1); + idLabel = new QLabel(idString, m_mainBox, "synthIdLabel"); + } + idLabel->setFont(boldFont); + + if (rec.m_input) { + mainLayout->addMultiCellWidget(rec.m_input->getWidget(), 1, 1, col, col + 1); + } + mainLayout->addMultiCellWidget(rec.m_output->getWidget(), 2, 2, col, col + 1); + // mainLayout->addWidget(idLabel, 2, col, Qt::AlignCenter); + // mainLayout->addWidget(rec.m_pan, 2, col+1, Qt::AlignLeft); + + mainLayout->addMultiCellWidget(idLabel, 0, 0, col, col + 1, Qt::AlignCenter); + mainLayout->addWidget(rec.m_pan, 5, col, Qt::AlignCenter); + + mainLayout->addWidget(rec.m_fader, 3, col, Qt::AlignCenter); + mainLayout->addWidget(rec.m_meter, 3, col + 1, Qt::AlignCenter); + + // commented out until implemented + // mainLayout->addWidget(rec.m_muteButton, 4, col); + // mainLayout->addWidget(rec.m_soloButton, 4, col+1); + rec.m_muteButton->hide(); + rec.m_soloButton->hide(); + + // mainLayout->addWidget(rec.m_recordButton, 5, col); + // mainLayout->addWidget(rec.m_stereoButton, 5, col+1); + + rec.m_recordButton->hide(); + mainLayout->addWidget(rec.m_stereoButton, 5, col + 1); + + if (rec.m_pluginBox) { + mainLayout->addMultiCellWidget(rec.m_pluginBox, 6, 6, col, col + 1); + } + + m_faders[(*i)->getId()] = rec; + updateFader((*i)->getId()); + updateRouteButtons((*i)->getId()); + updateStereoButton((*i)->getId()); + updatePluginButtons((*i)->getId()); + + if (rec.m_input) { + connect(rec.m_input, SIGNAL(changed()), + this, SLOT(slotInputChanged())); + } + + connect(rec.m_output, SIGNAL(changed()), + this, SLOT(slotOutputChanged())); + + connect(rec.m_fader, SIGNAL(faderChanged(float)), + this, SLOT(slotFaderLevelChanged(float))); + + connect(rec.m_pan, SIGNAL(valueChanged(float)), + this, SLOT(slotPanChanged(float))); + + connect(rec.m_soloButton, SIGNAL(clicked()), + this, SLOT(slotSoloChanged())); + + connect(rec.m_muteButton, SIGNAL(clicked()), + this, SLOT(slotMuteChanged())); + + connect(rec.m_stereoButton, SIGNAL(clicked()), + this, SLOT(slotChannelsChanged())); + + connect(rec.m_recordButton, SIGNAL(clicked()), + this, SLOT(slotRecordChanged())); + + ++count; + + mainLayout->addMultiCell(new QSpacerItem(2, 0), 0, 6, col + 2, col + 2); + + col += 3; + } + + count = 1; + + for (BussList::iterator i = busses.begin(); + i != busses.end(); ++i) { + + if (i == busses.begin()) + continue; // that one's the master + + FaderRec rec; + rec.m_populated = true; + + rec.m_pan = new Rotary + (m_mainBox, -100.0, 100.0, 1.0, 5.0, 0.0, 20, + Rotary::NoTicks, false, true); + rec.m_pan->setKnobColour(GUIPalette::getColour(GUIPalette::RotaryPastelBlue)); + + QToolTip::add + (rec.m_pan, i18n("Pan")); + + rec.m_fader = new Fader + (AudioLevel::LongFader, 20, 240, m_mainBox); + rec.m_meter = new AudioVUMeter + (m_mainBox, VUMeter::AudioPeakHoldIECLong, true, false, 20, 240); + + QToolTip::add + (rec.m_fader, i18n("Audio level")); + QToolTip::add + (rec.m_meter, i18n("Audio level")); + + rec.m_muteButton = new QPushButton(m_mainBox); + rec.m_muteButton->setText("M"); + rec.m_muteButton->setToggleButton(true); + rec.m_muteButton->setFlat(true); + + QToolTip::add + (rec.m_muteButton, i18n("Mute")); + + rec.m_pluginBox = new QVBox(m_mainBox); + + for (int p = 0; p < 5; ++p) { + QPushButton *plugin = new QPushButton(rec.m_pluginBox, "pluginButton"); + plugin->setText(i18n("")); + plugin->setMaximumWidth(45); + QToolTip::add + (plugin, i18n("Audio plugin button")); + rec.m_plugins.push_back(plugin); + connect(plugin, SIGNAL(clicked()), + this, SLOT(slotSelectPlugin())); + } + + QLabel *idLabel = new QLabel(i18n("Sub %1").arg(count), m_mainBox, "subMaster"); + idLabel->setFont(boldFont); + + // mainLayout->addWidget(idLabel, 2, col, Qt::AlignCenter); + mainLayout->addMultiCellWidget(idLabel, 0, 0, col, col + 1, Qt::AlignCenter); + + // mainLayout->addWidget(rec.m_pan, 2, col+1, Qt::AlignLeft); + mainLayout->addMultiCellWidget(rec.m_pan, 5, 5, col, col + 1, Qt::AlignCenter); + + mainLayout->addWidget(rec.m_fader, 3, col, Qt::AlignCenter); + mainLayout->addWidget(rec.m_meter, 3, col + 1, Qt::AlignCenter); + + // mainLayout->addMultiCellWidget(rec.m_muteButton, 4, 4, col, col+1); + rec.m_muteButton->hide(); + + if (rec.m_pluginBox) { + mainLayout->addMultiCellWidget(rec.m_pluginBox, 6, 6, col, col + 1); + } + + m_submasters.push_back(rec); + updateFader(count); + updatePluginButtons(count); + + connect(rec.m_fader, SIGNAL(faderChanged(float)), + this, SLOT(slotFaderLevelChanged(float))); + + connect(rec.m_pan, SIGNAL(valueChanged(float)), + this, SLOT(slotPanChanged(float))); + + connect(rec.m_muteButton, SIGNAL(clicked()), + this, SLOT(slotMuteChanged())); + + ++count; + + mainLayout->addMultiCell(new QSpacerItem(2, 0), 0, 6, col + 2, col + 2); + + col += 3; + } + + if (busses.size() > 0) { + + FaderRec rec; + rec.m_populated = true; + + rec.m_fader = new Fader + (AudioLevel::LongFader, 20, 240, m_mainBox); + rec.m_meter = new AudioVUMeter + (m_mainBox, VUMeter::AudioPeakHoldIEC, true, false, 20, 240); + + QToolTip::add + (rec.m_fader, i18n("Audio master output level")); + QToolTip::add + (rec.m_meter, i18n("Audio master output level")); + + rec.m_muteButton = new QPushButton(m_mainBox); + rec.m_muteButton->setText("M"); + rec.m_muteButton->setToggleButton(true); + rec.m_muteButton->setFlat(true); + + QLabel *idLabel = new QLabel(i18n("Master"), m_mainBox); + idLabel->setFont(boldFont); + + mainLayout->addMultiCellWidget(idLabel, 0, 0, col, col + 1, Qt::AlignCenter); + mainLayout->addWidget(rec.m_fader, 3, col, Qt::AlignCenter); + mainLayout->addWidget(rec.m_meter, 3, col + 1, Qt::AlignCenter); + + // mainLayout->addMultiCellWidget(rec.m_muteButton, 4, 4, col, col+1); + rec.m_muteButton->hide(); + + mainLayout->addMultiCell(new QSpacerItem(2, 0), 0, 6, col + 2, col + 2); + + m_master = rec; + updateFader(0); + + connect(rec.m_fader, SIGNAL(faderChanged(float)), + this, SLOT(slotFaderLevelChanged(float))); + + connect(rec.m_muteButton, SIGNAL(clicked()), + this, SLOT(slotMuteChanged())); + } + + m_mainBox->show(); + + slotUpdateFaderVisibility(); + slotUpdateSynthFaderVisibility(); + slotUpdateSubmasterVisibility(); + slotUpdatePluginButtonVisibility(); + + adjustSize(); +} + +bool +AudioMixerWindow::isInstrumentAssigned(InstrumentId id) +{ + Composition::trackcontainer &tracks = + m_document->getComposition().getTracks(); + + for (Composition::trackcontainer::iterator ti = + tracks.begin(); ti != tracks.end(); ++ti) { + if (ti->second->getInstrument() == id) { + return true; + } + } + + return false; +} + +void +AudioMixerWindow::slotTrackAssignmentsChanged() +{ + for (FaderMap::iterator i = m_faders.begin(); i != m_faders.end(); ++i) { + + InstrumentId id = i->first; + bool assigned = isInstrumentAssigned(id); + + if (assigned != i->second.m_populated) { + // found an inconsistency + populate(); + return ; + } + } +} + +void +AudioMixerWindow::slotUpdateInstrument(InstrumentId id) +{ + RG_DEBUG << "AudioMixerWindow::slotUpdateInstrument(" << id << ")" << endl; + + blockSignals(true); + + updateFader(id); + updateStereoButton(id); + updateRouteButtons(id); + updatePluginButtons(id); + updateMiscButtons(id); + + blockSignals(false); +} + +void +AudioMixerWindow::slotPluginSelected(InstrumentId id, + int index, int plugin) +{ + if (id >= (int)AudioInstrumentBase) { + + FaderRec &rec = m_faders[id]; + if (!rec.m_populated || !rec.m_pluginBox) + return ; + + // nowhere to display synth plugin info yet + if (index >= rec.m_plugins.size()) + return ; + + if (plugin == -1) { + + rec.m_plugins[index]->setText(i18n("")); + QToolTip::add + (rec.m_plugins[index], i18n("")); + + rec.m_plugins[index]->setPaletteBackgroundColor + (kapp->palette(). + color(QPalette::Active, QColorGroup::Button)); + + } else { + + AudioPlugin *pluginClass + = m_document->getPluginManager()->getPlugin(plugin); + + QColor pluginBgColour = + kapp->palette().color(QPalette::Active, QColorGroup::Light); + + if (pluginClass) { + rec.m_plugins[index]-> + setText(pluginClass->getLabel()); + QToolTip::add + (rec.m_plugins[index], pluginClass->getLabel()); + + pluginBgColour = pluginClass->getColour(); + } + + + rec.m_plugins[index]->setPaletteForegroundColor(Qt::white); + rec.m_plugins[index]->setPaletteBackgroundColor(pluginBgColour); + } + } else if (id > 0 && id <= m_submasters.size()) { + + FaderRec &rec = m_submasters[id - 1]; + if (!rec.m_populated || !rec.m_pluginBox) + return ; + if (index >= rec.m_plugins.size()) + return ; + + if (plugin == -1) { + + rec.m_plugins[index]->setText(i18n("")); + QToolTip::add + (rec.m_plugins[index], i18n("")); + + rec.m_plugins[index]->setPaletteBackgroundColor + (kapp->palette(). + color(QPalette::Active, QColorGroup::Button)); + + } else { + + AudioPlugin *pluginClass + = m_document->getPluginManager()->getPlugin(plugin); + + QColor pluginBgColour = + kapp->palette().color(QPalette::Active, QColorGroup::Light); + + if (pluginClass) { + rec.m_plugins[index]-> + setText(pluginClass->getLabel()); + QToolTip::add + (rec.m_plugins[index], pluginClass->getLabel()); + + pluginBgColour = pluginClass->getColour(); + } + + + rec.m_plugins[index]->setPaletteForegroundColor(Qt::white); + rec.m_plugins[index]->setPaletteBackgroundColor(pluginBgColour); + } + } +} + +void +AudioMixerWindow::slotPluginBypassed(InstrumentId instrumentId, + int , bool ) +{ + RG_DEBUG << "AudioMixerWindow::slotPluginBypassed(" << instrumentId << ")" << endl; + + updatePluginButtons(instrumentId); +} + +void +AudioMixerWindow::updateFader(int id) +{ + if (id == -1) { + + // This used to be the special code for updating the monitor fader. + return ; + + } else if (id >= (int)AudioInstrumentBase) { + + FaderRec &rec = m_faders[id]; + if (!rec.m_populated) + return ; + Instrument *instrument = m_studio->getInstrumentById(id); + + rec.m_fader->blockSignals(true); + rec.m_fader->setFader(instrument->getLevel()); + rec.m_fader->blockSignals(false); + + rec.m_pan->blockSignals(true); + rec.m_pan->setPosition(instrument->getPan() - 100); + rec.m_pan->blockSignals(false); + + } else { + + FaderRec &rec = (id == 0 ? m_master : m_submasters[id - 1]); + BussList busses = m_studio->getBusses(); + Buss *buss = busses[id]; + + rec.m_fader->blockSignals(true); + rec.m_fader->setFader(buss->getLevel()); + rec.m_fader->blockSignals(false); + + if (rec.m_pan) { + rec.m_pan->blockSignals(true); + rec.m_pan->setPosition(buss->getPan() - 100); + rec.m_pan->blockSignals(false); + } + } +} + +void +AudioMixerWindow::updateRouteButtons(int id) +{ + if (id >= (int)AudioInstrumentBase) { + FaderRec &rec = m_faders[id]; + if (!rec.m_populated) + return ; + if (rec.m_input) + rec.m_input->slotRepopulate(); + rec.m_output->slotRepopulate(); + } +} + +void +AudioMixerWindow::updateStereoButton(int id) +{ + if (id >= (int)AudioInstrumentBase) { + + FaderRec &rec = m_faders[id]; + if (!rec.m_populated) + return ; + Instrument *i = m_studio->getInstrumentById(id); + + bool stereo = (i->getAudioChannels() > 1); + if (stereo == rec.m_stereoness) + return ; + + rec.m_stereoness = stereo; + + if (stereo) + rec.m_stereoButton->setPixmap(m_stereoPixmap); + else + rec.m_stereoButton->setPixmap(m_monoPixmap); + } +} + +void +AudioMixerWindow::updateMiscButtons(int ) +{ + //... complications here, because the mute/solo status is actually + // per-track rather than per-instrument... doh. +} + +void +AudioMixerWindow::updatePluginButtons(int id) +{ + FaderRec *rec = 0; + PluginContainer *container = 0; + + if (id >= (int)AudioInstrumentBase) { + + container = m_studio->getInstrumentById(id); + rec = &m_faders[id]; + if (!rec->m_populated || !rec->m_pluginBox) + return ; + + } else { + + BussList busses = m_studio->getBusses(); + if (busses.size() > id) { + container = busses[id]; + } + rec = &m_submasters[id - 1]; + if (!rec->m_populated || !rec->m_pluginBox) + return ; + } + + if (rec && container) { + + for (unsigned int i = 0; i < rec->m_plugins.size(); i++) { + + bool used = false; + bool bypass = false; + QColor pluginBgColour = + kapp->palette().color(QPalette::Active, QColorGroup::Light); + + rec->m_plugins[i]->show(); + + AudioPluginInstance *inst = container->getPlugin(i); + + if (inst && inst->isAssigned()) { + + AudioPlugin *pluginClass + = m_document->getPluginManager()->getPlugin( + m_document->getPluginManager()-> + getPositionByIdentifier(inst->getIdentifier().c_str())); + + if (pluginClass) { + rec->m_plugins[i]->setText(pluginClass->getLabel()); + QToolTip::add + (rec->m_plugins[i], pluginClass->getLabel()); + + pluginBgColour = pluginClass->getColour(); + } + + used = true; + bypass = inst->isBypassed(); + + } else { + + rec->m_plugins[i]->setText(i18n("")); + QToolTip::add + (rec->m_plugins[i], i18n("")); + + if (inst) + bypass = inst->isBypassed(); + } + + if (bypass) { + + rec->m_plugins[i]->setPaletteForegroundColor + (kapp->palette(). + color(QPalette::Active, QColorGroup::Button)); + + rec->m_plugins[i]->setPaletteBackgroundColor + (kapp->palette(). + color(QPalette::Active, QColorGroup::ButtonText)); + + } else if (used) { + + rec->m_plugins[i]->setPaletteForegroundColor(Qt::white); + rec->m_plugins[i]->setPaletteBackgroundColor(pluginBgColour); + + + } else { + + rec->m_plugins[i]->setPaletteForegroundColor + (kapp->palette(). + color(QPalette::Active, QColorGroup::ButtonText)); + + rec->m_plugins[i]->setPaletteBackgroundColor + (kapp->palette(). + color(QPalette::Active, QColorGroup::Button)); + } + } + } +} + +void +AudioMixerWindow::slotSelectPlugin() +{ + const QObject *s = sender(); + + for (FaderMap::iterator i = m_faders.begin(); + i != m_faders.end(); ++i) { + + int index = 0; + if (!i->second.m_populated || !i->second.m_pluginBox) + continue; + + for (std::vector::iterator pli = i->second.m_plugins.begin(); + pli != i->second.m_plugins.end(); ++pli) { + + if (*pli == s) { + + emit selectPlugin(this, i->first, index); + return ; + } + + ++index; + } + } + + + int b = 1; + + for (FaderVector::iterator i = m_submasters.begin(); + i != m_submasters.end(); ++i) { + + int index = 0; + if (!i->m_populated || !i->m_pluginBox) + continue; + + for (std::vector::iterator pli = i->m_plugins.begin(); + pli != i->m_plugins.end(); ++pli) { + + if (*pli == s) { + + emit selectPlugin(this, b, index); + return ; + } + + ++index; + } + + ++b; + } +} + +void +AudioMixerWindow::slotInputChanged() +{ + const QObject *s = sender(); + + for (FaderMap::iterator i = m_faders.begin(); + i != m_faders.end(); ++i) { + + if (i->second.m_input == s) + emit instrumentParametersChanged(i->first); + } +} + +void +AudioMixerWindow::slotOutputChanged() +{ + const QObject *s = sender(); + + for (FaderMap::iterator i = m_faders.begin(); + i != m_faders.end(); ++i) { + + if (i->second.m_output == s) + emit instrumentParametersChanged(i->first); + } +} + +void +AudioMixerWindow::sendControllerRefresh() +{ + //!!! really want some notification of whether we have an external controller! + int controllerChannel = 0; + + for (FaderMap::iterator i = m_faders.begin(); i != m_faders.end(); ++i) { + + if (controllerChannel >= 16) + break; + + Instrument *instrument = + m_studio->getInstrumentById(i->first); + + int value = AudioLevel::dB_to_fader + (instrument->getLevel(), 127, AudioLevel::LongFader); + MappedEvent mE(instrument->getId(), + MappedEvent::MidiController, + MIDI_CONTROLLER_VOLUME, + MidiByte(value)); + mE.setRecordedChannel(controllerChannel); + mE.setRecordedDevice(Device::CONTROL_DEVICE); + StudioControl::sendMappedEvent(mE); + + int ipan = (int(instrument->getPan()) * 64) / 100; + if (ipan < 0) + ipan = 0; + if (ipan > 127) + ipan = 127; + MappedEvent mEp(instrument->getId(), + MappedEvent::MidiController, + MIDI_CONTROLLER_PAN, + MidiByte(ipan)); + mEp.setRecordedChannel(controllerChannel); + mEp.setRecordedDevice(Device::CONTROL_DEVICE); + StudioControl::sendMappedEvent(mEp); + + ++controllerChannel; + } +} + +void +AudioMixerWindow::slotFaderLevelChanged(float dB) +{ + const QObject *s = sender(); + + BussList busses = m_studio->getBusses(); + + if (m_master.m_fader == s) { + + if (busses.size() > 0) { + StudioControl::setStudioObjectProperty + (MappedObjectId(busses[0]->getMappedId()), + MappedAudioBuss::Level, + MappedObjectValue(dB)); + busses[0]->setLevel(dB); + } + + return ; + } + + int index = 1; + + for (FaderVector::iterator i = m_submasters.begin(); + i != m_submasters.end(); ++i) { + + if (i->m_fader == s) { + if ((int)busses.size() > index) { + StudioControl::setStudioObjectProperty + (MappedObjectId(busses[index]->getMappedId()), + MappedAudioBuss::Level, + MappedObjectValue(dB)); + busses[index]->setLevel(dB); + } + + return ; + } + + ++index; + } + + int controllerChannel = 0; + + for (FaderMap::iterator i = m_faders.begin(); + i != m_faders.end(); ++i) { + + if (i->second.m_fader == s) { + + Instrument *instrument = + m_studio->getInstrumentById(i->first); + + if (instrument) { + StudioControl::setStudioObjectProperty + (MappedObjectId + (instrument->getMappedId()), + MappedAudioFader::FaderLevel, + MappedObjectValue(dB)); + instrument->setLevel(dB); + } + + // send out to external controllers as well. + //!!! really want some notification of whether we have any! + if (controllerChannel < 16) { + int value = AudioLevel::dB_to_fader + (dB, 127, AudioLevel::LongFader); + MappedEvent mE(instrument->getId(), + MappedEvent::MidiController, + MIDI_CONTROLLER_VOLUME, + MidiByte(value)); + mE.setRecordedChannel(controllerChannel); + mE.setRecordedDevice(Device::CONTROL_DEVICE); + StudioControl::sendMappedEvent(mE); + } + + emit instrumentParametersChanged(i->first); + } + + ++controllerChannel; + } +} + +void +AudioMixerWindow::slotPanChanged(float pan) +{ + const QObject *s = sender(); + + BussList busses = m_studio->getBusses(); + + int index = 1; + + for (FaderVector::iterator i = m_submasters.begin(); + i != m_submasters.end(); ++i) { + + if (i->m_pan == s) { + if ((int)busses.size() > index) { + StudioControl::setStudioObjectProperty + (MappedObjectId(busses[index]->getMappedId()), + MappedAudioBuss::Pan, + MappedObjectValue(pan)); + busses[index]->setPan(MidiByte(pan + 100.0)); + } + return ; + } + + ++index; + } + + int controllerChannel = 0; + + for (FaderMap::iterator i = m_faders.begin(); + i != m_faders.end(); ++i) { + + if (i->second.m_pan == s) { + + Instrument *instrument = + m_studio->getInstrumentById(i->first); + + if (instrument) { + StudioControl::setStudioObjectProperty + (instrument->getMappedId(), + MappedAudioFader::Pan, + MappedObjectValue(pan)); + instrument->setPan(MidiByte(pan + 100.0)); + } + + // send out to external controllers as well. + //!!! really want some notification of whether we have any! + if (controllerChannel < 16) { + int ipan = (int(instrument->getPan()) * 64) / 100; + if (ipan < 0) + ipan = 0; + if (ipan > 127) + ipan = 127; + MappedEvent mE(instrument->getId(), + MappedEvent::MidiController, + MIDI_CONTROLLER_PAN, + MidiByte(ipan)); + mE.setRecordedChannel(controllerChannel); + mE.setRecordedDevice(Device::CONTROL_DEVICE); + StudioControl::sendMappedEvent(mE); + } + + emit instrumentParametersChanged(i->first); + } + + ++controllerChannel; + } +} + +void +AudioMixerWindow::slotChannelsChanged() +{ + const QObject *s = sender(); + + // channels are only switchable on instruments + + //!!! need to reconnect input, or change input channel number anyway + + + for (FaderMap::iterator i = m_faders.begin(); + i != m_faders.end(); ++i) { + + if (s == i->second.m_stereoButton) { + + Instrument *instrument = + m_studio->getInstrumentById(i->first); + + if (instrument) { + instrument->setAudioChannels + ((instrument->getAudioChannels() > 1) ? 1 : 2); + updateStereoButton(instrument->getId()); + updateRouteButtons(instrument->getId()); + + emit instrumentParametersChanged(i->first); + + return ; + } + } + } +} + +void +AudioMixerWindow::slotSoloChanged() +{ + //... +} + +void +AudioMixerWindow::slotMuteChanged() +{ + //... +} + +void +AudioMixerWindow::slotRecordChanged() +{ + //... +} + +void +AudioMixerWindow::updateMeters(SequencerMapper *mapper) +{ + for (FaderMap::iterator i = m_faders.begin(); i != m_faders.end(); ++i) { + + InstrumentId id = i->first; + FaderRec &rec = i->second; + if (!rec.m_populated) + continue; + + LevelInfo info; + + if (mapper->getInstrumentLevelForMixer(id, info)) { + + // The values passed through are long-fader values + float dBleft = AudioLevel::fader_to_dB + (info.level, 127, AudioLevel::LongFader); + + if (rec.m_stereoness) { + float dBright = AudioLevel::fader_to_dB + (info.levelRight, 127, AudioLevel::LongFader); + + rec.m_meter->setLevel(dBleft, dBright); + + } else { + rec.m_meter->setLevel(dBleft); + } + } + } + + for (unsigned int i = 0; i < m_submasters.size(); ++i) { + + FaderRec &rec = m_submasters[i]; + + LevelInfo info; + if (!mapper->getSubmasterLevel(i, info)) + continue; + + // The values passed through are long-fader values + float dBleft = AudioLevel::fader_to_dB + (info.level, 127, AudioLevel::LongFader); + float dBright = AudioLevel::fader_to_dB + (info.levelRight, 127, AudioLevel::LongFader); + + rec.m_meter->setLevel(dBleft, dBright); + } + + updateMonitorMeters(mapper); + + LevelInfo masterInfo; + if (mapper->getMasterLevel(masterInfo)) { + + float dBleft = AudioLevel::fader_to_dB + (masterInfo.level, 127, AudioLevel::LongFader); + float dBright = AudioLevel::fader_to_dB + (masterInfo.levelRight, 127, AudioLevel::LongFader); + + m_master.m_meter->setLevel(dBleft, dBright); + } +} + +void +AudioMixerWindow::updateMonitorMeters(SequencerMapper *mapper) +{ + // only show monitor levels when quiescent or when recording (as + // record levels) + if (m_document->getSequenceManager() && + m_document->getSequenceManager()->getTransportStatus() == PLAYING) { + return ; + } + + Composition &comp = m_document->getComposition(); + Composition::trackcontainer &tracks = comp.getTracks(); + + for (FaderMap::iterator i = m_faders.begin(); i != m_faders.end(); ++i) { + + InstrumentId id = i->first; + FaderRec &rec = i->second; + if (!rec.m_populated) + continue; + + LevelInfo info; + + if (mapper->getInstrumentRecordLevelForMixer(id, info)) { + + bool armed = false; + + for (Composition::trackcontainer::iterator ti = + tracks.begin(); ti != tracks.end(); ++ti) { + if (ti->second->getInstrument() == id) { + if (comp.isTrackRecording(ti->second->getId())) { + armed = true; + break; + } + } + } + + if (!armed) + continue; + + // The values passed through are long-fader values + float dBleft = AudioLevel::fader_to_dB + (info.level, 127, AudioLevel::LongFader); + + if (rec.m_stereoness) { + float dBright = AudioLevel::fader_to_dB + (info.levelRight, 127, AudioLevel::LongFader); + + rec.m_meter->setRecordLevel(dBleft, dBright); + + } else { + rec.m_meter->setRecordLevel(dBleft); + } + } + } +} + +void +AudioMixerWindow::slotControllerDeviceEventReceived(MappedEvent *e, + const void *preferredCustomer) +{ + if (preferredCustomer != this) + return ; + RG_DEBUG << "AudioMixerWindow::slotControllerDeviceEventReceived: this one's for me" << endl; + raise(); + + // get channel number n from event + // update instrument for nth fader in m_faders + + if (e->getType() != MappedEvent::MidiController) + return ; + unsigned int channel = e->getRecordedChannel(); + MidiByte controller = e->getData1(); + MidiByte value = e->getData2(); + + int count = 0; + for (FaderMap::iterator i = m_faders.begin(); i != m_faders.end(); ++i) { + + if (count < channel) { + ++count; + continue; + } + + Instrument *instrument = + m_studio->getInstrumentById(i->first); + if (!instrument) + continue; + + switch (controller) { + + case MIDI_CONTROLLER_VOLUME: { + float level = AudioLevel::fader_to_dB + (value, 127, AudioLevel::LongFader); + + StudioControl::setStudioObjectProperty + (instrument->getMappedId(), + MappedAudioFader::FaderLevel, + MappedObjectValue(level)); + + instrument->setLevel(level); + break; + } + + case MIDI_CONTROLLER_PAN: { + MidiByte ipan = MidiByte((value / 64.0) * 100.0 + 0.01); + + StudioControl::setStudioObjectProperty + (instrument->getMappedId(), + MappedAudioFader::Pan, + MappedObjectValue(float(ipan) - 100.0)); + + instrument->setPan(ipan); + break; + } + + default: + break; + } + + slotUpdateInstrument(i->first); + emit instrumentParametersChanged(i->first); + + break; + } +} + +void +AudioMixerWindow::slotSetInputCountFromAction() +{ + const QObject *s = sender(); + QString name = s->name(); + + if (name.left(7) == "inputs_") { + + int count = name.right(name.length() - 7).toInt(); + + RecordInList ins = m_studio->getRecordIns(); + int current = ins.size(); + + if (count == current) + return ; + + m_studio->clearRecordIns(); // leaves the default 1 + + for (int i = 1; i < count; ++i) { + m_studio->addRecordIn(new RecordIn()); + } + } + + m_document->initialiseStudio(); + + for (FaderMap::iterator i = m_faders.begin(); + i != m_faders.end(); ++i) { + updateRouteButtons(i->first); + } +} + +void +AudioMixerWindow::slotSetSubmasterCountFromAction() +{ + const QObject *s = sender(); + QString name = s->name(); + + if (name.left(11) == "submasters_") { + + int count = name.right(name.length() - 11).toInt(); + + BussList busses = m_studio->getBusses(); + int current = busses.size(); + + // offset by 1 generally to take into account the fact that + // the first buss in the studio is the master, not a submaster + + if (count + 1 == current) + return ; + + BussList dups; + for (int i = 0; i < count; ++i) { + if (i + 1 < int(busses.size())) { + dups.push_back(new Buss(*busses[i + 1])); + } else { + dups.push_back(new Buss(i + 1)); + } + } + + m_studio->clearBusses(); + + for (BussList::iterator i = dups.begin(); + i != dups.end(); ++i) { + m_studio->addBuss(*i); + } + } + + m_document->initialiseStudio(); + + populate(); +} + +void AudioMixerWindow::FaderRec::setVisible(bool visible) +{ + if (visible) { + if (m_input) + m_input->getWidget()->show(); + if (m_output) + m_output->getWidget()->show(); + if (m_pan) + m_pan->show(); + if (m_fader) + m_fader->show(); + if (m_meter) + m_meter->show(); + // commented out until implemented + // if (m_muteButton) m_muteButton->show(); + // if (m_soloButton) m_soloButton->show(); + // if (m_recordButton) m_recordButton->show(); + if (m_stereoButton) + m_stereoButton->show(); + + } else { + + if (m_input) + m_input->getWidget()->hide(); + if (m_output) + m_output->getWidget()->hide(); + if (m_pan) + m_pan->hide(); + if (m_fader) + m_fader->hide(); + if (m_meter) + m_meter->hide(); + // commented out until implemented + // if (m_muteButton) m_muteButton->hide(); + // if (m_soloButton) m_soloButton->hide(); + // if (m_recordButton) m_recordButton->hide(); + if (m_stereoButton) + m_stereoButton->hide(); + } + + setPluginButtonsVisible(visible); + +} + +void +AudioMixerWindow::FaderRec::setPluginButtonsVisible(bool visible) +{ + if (!m_pluginBox) + return ; + + if (visible) { + m_pluginBox->show(); + } else { + m_pluginBox->hide(); + } +} + +void +AudioMixerWindow::slotToggleFaders() +{ + m_studio->setMixerDisplayOptions(m_studio->getMixerDisplayOptions() ^ + MIXER_OMIT_FADERS); + + slotUpdateFaderVisibility(); +} + +void +AudioMixerWindow::slotUpdateFaderVisibility() +{ + bool d = !(m_studio->getMixerDisplayOptions() & MIXER_OMIT_FADERS); + + KToggleAction *action = dynamic_cast + (actionCollection()->action("show_audio_faders")); + if (action) { + action->setChecked(d); + } + + RG_DEBUG << "AudioMixerWindow::slotUpdateFaderVisibility: visiblility is " << d << " (options " << m_studio->getMixerDisplayOptions() << ")" << endl; + + for (FaderMap::iterator i = m_faders.begin(); i != m_faders.end(); ++i) { + if (i->first < SoftSynthInstrumentBase) { + FaderRec rec = i->second; + rec.setVisible(d); + } + } + + toggleNamedWidgets(d, "audioIdLabel"); + + adjustSize(); +} + +void +AudioMixerWindow::slotToggleSynthFaders() +{ + m_studio->setMixerDisplayOptions(m_studio->getMixerDisplayOptions() ^ + MIXER_OMIT_SYNTH_FADERS); + + slotUpdateSynthFaderVisibility(); +} + +void +AudioMixerWindow::slotUpdateSynthFaderVisibility() +{ + KToggleAction *action = dynamic_cast + (actionCollection()->action("show_synth_faders")); + if (!action) + return ; + + action->setChecked(!(m_studio->getMixerDisplayOptions() & + MIXER_OMIT_SYNTH_FADERS)); + + for (FaderMap::iterator i = m_faders.begin(); i != m_faders.end(); ++i) { + if (i->first >= SoftSynthInstrumentBase) { + FaderRec rec = i->second; + rec.setVisible(action->isChecked()); + } + } + + toggleNamedWidgets(action->isChecked(), "synthIdLabel"); + + adjustSize(); +} + +void +AudioMixerWindow::slotToggleSubmasters() +{ + m_studio->setMixerDisplayOptions(m_studio->getMixerDisplayOptions() ^ + MIXER_OMIT_SUBMASTERS); + + slotUpdateSubmasterVisibility(); +} + +void +AudioMixerWindow::slotUpdateSubmasterVisibility() +{ + KToggleAction *action = dynamic_cast + (actionCollection()->action("show_audio_submasters")); + if (!action) + return ; + + action->setChecked(!(m_studio->getMixerDisplayOptions() & + MIXER_OMIT_SUBMASTERS)); + + for (FaderVector::iterator i = m_submasters.begin(); i != m_submasters.end(); ++i) { + FaderRec rec = *i; + rec.setVisible(action->isChecked()); + } + + toggleNamedWidgets(action->isChecked(), "subMaster"); + + adjustSize(); +} + +void +AudioMixerWindow::slotTogglePluginButtons() +{ + m_studio->setMixerDisplayOptions(m_studio->getMixerDisplayOptions() ^ + MIXER_OMIT_PLUGINS); + + slotUpdatePluginButtonVisibility(); +} + +void +AudioMixerWindow::slotUpdatePluginButtonVisibility() +{ + KToggleAction *action = dynamic_cast + (actionCollection()->action("show_plugin_buttons")); + if (!action) + return ; + + action->setChecked(!(m_studio->getMixerDisplayOptions() & + MIXER_OMIT_PLUGINS)); + + for (FaderMap::iterator i = m_faders.begin(); i != m_faders.end(); ++i) { + FaderRec rec = i->second; + rec.setPluginButtonsVisible(action->isChecked()); + } + + adjustSize(); +} + +void +AudioMixerWindow::slotToggleUnassignedFaders() +{ + KToggleAction *action = dynamic_cast + (actionCollection()->action("show_unassigned_faders")); + if (!action) + return ; + + m_studio->setMixerDisplayOptions(m_studio->getMixerDisplayOptions() ^ + MIXER_SHOW_UNASSIGNED_FADERS); + + action->setChecked(m_studio->getMixerDisplayOptions() & + MIXER_SHOW_UNASSIGNED_FADERS); + + populate(); +} + +void +AudioMixerWindow::toggleNamedWidgets(bool show, const char* const name) +{ + QLayoutIterator it = m_mainBox->layout()->iterator(); + QLayoutItem *child; + while ( (child = it.current()) != 0 ) { + QWidget * widget = child->widget(); + if (widget && widget->name() && !strcmp(widget->name(), name)) { + if (show) + widget->show(); + else + widget->hide(); + } + + ++it; + } + +} + +} +#include "AudioMixerWindow.moc" diff --git a/src/gui/studio/AudioMixerWindow.h b/src/gui/studio/AudioMixerWindow.h new file mode 100644 index 0000000..99829de --- /dev/null +++ b/src/gui/studio/AudioMixerWindow.h @@ -0,0 +1,191 @@ + +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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. +*/ + +#ifndef _RG_AUDIOMIXERWINDOW_H_ +#define _RG_AUDIOMIXERWINDOW_H_ + +#include "base/MidiProgram.h" +#include +#include "MixerWindow.h" +#include +#include + + +class QWidget; +class QVBox; +class QPushButton; +class QHBox; +class QFrame; + + +namespace Rosegarden +{ + +class SequencerMapper; +class Rotary; +class RosegardenGUIDoc; +class MappedEvent; +class Fader; +class AudioVUMeter; +class AudioRouteMenu; + + +class AudioMixerWindow : public MixerWindow +{ + Q_OBJECT + +public: + AudioMixerWindow(QWidget *parent, RosegardenGUIDoc *document); + ~AudioMixerWindow(); + + void updateMeters(SequencerMapper *mapper); + void updateMonitorMeters(SequencerMapper *mapper); + +public slots: + void slotControllerDeviceEventReceived(MappedEvent *, + const void *); + +signals: + void selectPlugin(QWidget *, InstrumentId id, int index); + + void play(); + void stop(); + void fastForwardPlayback(); + void rewindPlayback(); + void fastForwardPlaybackToEnd(); + void rewindPlaybackToBeginning(); + void record(); + void panic(); + + // to be redirected to the instrument parameter box if necessary + void instrumentParametersChanged(InstrumentId); + +protected slots: + void slotFaderLevelChanged(float level); + void slotPanChanged(float value); + void slotInputChanged(); + void slotOutputChanged(); + void slotChannelsChanged(); + void slotSoloChanged(); + void slotMuteChanged(); + void slotRecordChanged(); + void slotSelectPlugin(); + + // to be called if something changes in an instrument parameter box + void slotUpdateInstrument(InstrumentId); + + void slotTrackAssignmentsChanged(); + + // from Plugin dialog + void slotPluginSelected(InstrumentId id, int index, int plugin); + void slotPluginBypassed(InstrumentId id, int pluginIndex, bool bp); + + void slotSetInputCountFromAction(); + void slotSetSubmasterCountFromAction(); + + void slotToggleFaders(); + void slotToggleSynthFaders(); + void slotToggleSubmasters(); + void slotTogglePluginButtons(); + void slotToggleUnassignedFaders(); + + void slotUpdateFaderVisibility(); + void slotUpdateSynthFaderVisibility(); + void slotUpdateSubmasterVisibility(); + void slotUpdatePluginButtonVisibility(); + +protected: + virtual void sendControllerRefresh(); + +private: + + void toggleNamedWidgets(bool show, const char* const); + + + // manage the various bits of it in horizontal/vertical slices + // with other faders: + + struct FaderRec { + + FaderRec() : + m_populated(false), + m_input(0), m_output(0), m_pan(0), m_fader(0), m_meter(0), + m_muteButton(0), m_soloButton(0), m_recordButton(0), + m_stereoButton(0), m_stereoness(false), m_pluginBox(0) + { } + + void setVisible(bool); + void setPluginButtonsVisible(bool); + + bool m_populated; + + AudioRouteMenu *m_input; + AudioRouteMenu *m_output; + + Rotary *m_pan; + Fader *m_fader; + AudioVUMeter *m_meter; + + QPushButton *m_muteButton; + QPushButton *m_soloButton; + QPushButton *m_recordButton; + QPushButton *m_stereoButton; + bool m_stereoness; + + QVBox *m_pluginBox; + std::vector m_plugins; + }; + + QHBox *m_surroundBox; + QFrame *m_mainBox; + + typedef std::map FaderMap; + FaderMap m_faders; + + typedef std::vector FaderVector; + FaderVector m_submasters; + FaderRec m_monitor; + FaderRec m_master; + + void depopulate(); + void populate(); + + bool isInstrumentAssigned(InstrumentId id); + + void updateFader(int id); // instrument id if large enough, monitor if -1, master/sub otherwise + void updateRouteButtons(int id); + void updateStereoButton(int id); + void updatePluginButtons(int id); + void updateMiscButtons(int id); + + QPixmap m_monoPixmap; + QPixmap m_stereoPixmap; +}; + + + +} + +#endif diff --git a/src/gui/studio/AudioPlugin.cpp b/src/gui/studio/AudioPlugin.cpp new file mode 100644 index 0000000..2cf3db2 --- /dev/null +++ b/src/gui/studio/AudioPlugin.cpp @@ -0,0 +1,78 @@ +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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 "AudioPlugin.h" + +#include "misc/Strings.h" +#include "base/AudioPluginInstance.h" +#include +#include + + +namespace Rosegarden +{ + +AudioPlugin::AudioPlugin(const QString &identifier, + const QString &name, + unsigned long uniqueId, + const QString &label, + const QString &author, + const QString ©right, + bool isSynth, + bool isGrouped, + const QString &category): + m_identifier(identifier), + m_name(name), + m_uniqueId(uniqueId), + m_label(label), + m_author(author), + m_copyright(copyright), + m_isSynth(isSynth), + m_isGrouped(isGrouped), + m_category(category), + m_colour(Qt::darkRed) +{} + +void +AudioPlugin::addPort(int number, + const QString &name, + PluginPort::PortType type, + PluginPort::PortDisplayHint hint, + PortData lowerBound, + PortData upperBound, + PortData defaultValue) +{ + PluginPort *port = new PluginPort(number, + qstrtostr(name), + type, + hint, + lowerBound, + upperBound, + defaultValue); + m_ports.push_back(port); + +} + +} diff --git a/src/gui/studio/AudioPlugin.h b/src/gui/studio/AudioPlugin.h new file mode 100644 index 0000000..591a43b --- /dev/null +++ b/src/gui/studio/AudioPlugin.h @@ -0,0 +1,117 @@ + +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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. +*/ + +#ifndef _RG_AUDIOPLUGIN_H_ +#define _RG_AUDIOPLUGIN_H_ + +#include "base/AudioPluginInstance.h" +#include +#include +#include + + + + +namespace Rosegarden +{ + + + +class AudioPlugin +{ +public: + AudioPlugin(const QString &identifier, + const QString &name, + unsigned long uniqueId, + const QString &label, + const QString &author, + const QString ©right, + bool isSynth, + bool isGrouped, + const QString &category); + + QString getIdentifier() const { return m_identifier; } + + QString getName() const { return m_name; } + unsigned long getUniqueId() const { return m_uniqueId; } + QString getLabel() const { return m_label; } + QString getAuthor() const { return m_author; } + QString getCopyright() const { return m_copyright; } + bool isSynth() const { return m_isSynth; } + bool isEffect() const { // true if >0 audio inputs + for (unsigned int i = 0; i < m_ports.size(); ++i) { + if ((m_ports[i]->getType() & PluginPort::Input) && + (m_ports[i]->getType() & PluginPort::Audio)) { + return true; + } + } + return false; + } + bool isGrouped() const { return m_isGrouped; } + QString getCategory() const { return m_category; } + + void addPort(int number, + const QString &name, + PluginPort::PortType type, + PluginPort::PortDisplayHint hint, + PortData lowerBound, + PortData upperBound, + PortData defaultVale); + + typedef std::vector::iterator PortIterator; + + PortIterator begin() { return m_ports.begin(); } + PortIterator end() { return m_ports.end(); } + + QColor getColour() const { return m_colour; } + void setColour(const QColor &colour) { m_colour = colour; } + +protected: + + QString m_identifier; + + QString m_name; + unsigned long m_uniqueId; + QString m_label; + QString m_author; + QString m_copyright; + bool m_isSynth; + bool m_isGrouped; + QString m_category; + + // our ports and associated hints + std::vector m_ports; + + // Colour of this activated plugin + // + QColor m_colour; +}; + +typedef std::vector::iterator PluginIterator; + + +} + +#endif diff --git a/src/gui/studio/AudioPluginClipboard.cpp b/src/gui/studio/AudioPluginClipboard.cpp new file mode 100644 index 0000000..54f5612 --- /dev/null +++ b/src/gui/studio/AudioPluginClipboard.cpp @@ -0,0 +1,32 @@ +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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 "AudioPluginClipboard.h" + + + +namespace Rosegarden +{ +} diff --git a/src/gui/studio/AudioPluginClipboard.h b/src/gui/studio/AudioPluginClipboard.h new file mode 100644 index 0000000..e31ed90 --- /dev/null +++ b/src/gui/studio/AudioPluginClipboard.h @@ -0,0 +1,52 @@ + +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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. +*/ + +#ifndef _RG_AUDIOPLUGINCLIPBOARD_H_ +#define _RG_AUDIOPLUGINCLIPBOARD_H_ + +#include +#include +#include + + + + +namespace Rosegarden +{ + + + +struct AudioPluginClipboard +{ + int m_pluginNumber; + std::map m_configuration; + std::string m_program; + std::vector m_controlValues; +}; + + +} + +#endif diff --git a/src/gui/studio/AudioPluginManager.cpp b/src/gui/studio/AudioPluginManager.cpp new file mode 100644 index 0000000..6b64085 --- /dev/null +++ b/src/gui/studio/AudioPluginManager.cpp @@ -0,0 +1,307 @@ +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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 "AudioPluginManager.h" + +#include "misc/Debug.h" +#include "AudioPluginClipboard.h" +#include "AudioPlugin.h" +#include "base/AudioPluginInstance.h" +#include "gui/application/RosegardenApplication.h" +#include "sound/PluginFactory.h" +#include "sound/PluginIdentifier.h" +#include +#include +#include +#include +#include + + +namespace Rosegarden +{ + +AudioPluginManager::AudioPluginManager() : + m_sampleRate(0), + m_enumerator(this) +{ +// std::cerr << "AudioPluginManager[" << this << "]::AudioPluginManager - " +// << "trace is "; +// std::cerr << kdBacktrace() << std::endl; + + + // fetch from sequencer + fetchSampleRate(); + + // Clear the plugin clipboard + // + m_pluginClipboard.m_pluginNumber = -1; + m_pluginClipboard.m_program = ""; + m_pluginClipboard.m_controlValues.clear(); + + m_enumerator.start(); +} + +AudioPluginManager::Enumerator::Enumerator(AudioPluginManager *manager) : + m_manager(manager), + m_done(false) +{} + +void +AudioPluginManager::Enumerator::run() +{ + QMutexLocker locker(&(m_manager->m_mutex)); + MappedObjectPropertyList rawPlugins; + + RG_DEBUG << "\n\nAudioPluginManager::Enumerator::run()\n\n" << endl; + + if (!rgapp->noSequencerMode()) { + // We only waste the time looking for plugins here if we + // know we're actually going to be able to use them. + PluginFactory::enumerateAllPlugins(rawPlugins); + } + + unsigned int i = 0; + + while (i < rawPlugins.size()) { + + QString identifier = rawPlugins[i++]; + QString name = rawPlugins[i++]; + unsigned long uniqueId = rawPlugins[i++].toLong(); + QString label = rawPlugins[i++]; + QString author = rawPlugins[i++]; + QString copyright = rawPlugins[i++]; + bool isSynth = ((rawPlugins[i++]).lower() == "true"); + bool isGrouped = ((rawPlugins[i++]).lower() == "true"); + QString category = rawPlugins[i++]; + unsigned int portCount = rawPlugins[i++].toInt(); + + // std::cerr << "PLUGIN: " << i << ": " << (identifier ? identifier : "(null)") << " unique id " << uniqueId << " / CATEGORY: \"" << (category ? category : "(null)") << "\"" << std::endl; + + AudioPlugin *aP = m_manager->addPlugin(identifier, + name, + uniqueId, + label, + author, + copyright, + isSynth, + isGrouped, + category); + + for (unsigned int j = 0; j < portCount; j++) { + + int number = rawPlugins[i++].toInt(); + name = rawPlugins[i++]; + PluginPort::PortType type = + PluginPort::PortType(rawPlugins[i++].toInt()); + PluginPort::PortDisplayHint hint = + PluginPort::PortDisplayHint(rawPlugins[i++].toInt()); + PortData lowerBound = rawPlugins[i++].toFloat(); + PortData upperBound = rawPlugins[i++].toFloat(); + PortData defaultValue = rawPlugins[i++].toFloat(); + + aP->addPort(number, + name, + type, + hint, + lowerBound, + upperBound, + defaultValue); + } + } + + m_done = true; + + RG_DEBUG << "\n\nAudioPluginManager::Enumerator::run() - done\n\n" << endl; +} + +AudioPlugin* +AudioPluginManager::addPlugin(const QString &identifier, + const QString &name, + unsigned long uniqueId, + const QString &label, + const QString &author, + const QString ©right, + bool isSynth, + bool isGrouped, + const QString &category) +{ + AudioPlugin *newPlugin = new AudioPlugin(identifier, + name, + uniqueId, + label, + author, + copyright, + isSynth, + isGrouped, + category); + m_plugins.push_back(newPlugin); + + return newPlugin; +} + +bool +AudioPluginManager::removePlugin(const QString &identifier) +{ + std::vector::iterator it = m_plugins.begin(); + + for (; it != m_plugins.end(); ++it) { + if ((*it)->getIdentifier() == identifier) { + delete *it; + m_plugins.erase(it); + return true; + } + } + + return false; +} + +std::vector +AudioPluginManager::getPluginNames() +{ + awaitEnumeration(); + + std::vector names; + + PluginIterator it = m_plugins.begin(); + + for (; it != m_plugins.end(); ++it) + names.push_back((*it)->getName()); + + return names; +} + +AudioPlugin* +AudioPluginManager::getPlugin(int number) +{ + awaitEnumeration(); + + if (number < 0 || number > (int(m_plugins.size()) - 1)) + return 0; + + return m_plugins[number]; +} + +int +AudioPluginManager::getPositionByIdentifier(QString identifier) +{ + awaitEnumeration(); + + int pos = 0; + PluginIterator it = m_plugins.begin(); + + for (; it != m_plugins.end(); ++it) { + if ((*it)->getIdentifier() == identifier) + return pos; + + pos++; + } + + pos = 0; + it = m_plugins.begin(); + for (; it != m_plugins.end(); ++it) { + if (PluginIdentifier::areIdentifiersSimilar((*it)->getIdentifier(), identifier)) + return pos; + + pos++; + } + + return -1; +} + +AudioPlugin* +AudioPluginManager::getPluginByIdentifier(QString identifier) +{ + awaitEnumeration(); + + PluginIterator it = m_plugins.begin(); + for (; it != m_plugins.end(); ++it) { + if ((*it)->getIdentifier() == identifier) + return (*it); + } + + it = m_plugins.begin(); + for (; it != m_plugins.end(); ++it) { + if (PluginIdentifier::areIdentifiersSimilar((*it)->getIdentifier(), identifier)) + return (*it); + } + + return 0; +} + +AudioPlugin* +AudioPluginManager::getPluginByUniqueId(unsigned long uniqueId) +{ + awaitEnumeration(); + + PluginIterator it = m_plugins.begin(); + for (; it != m_plugins.end(); ++it) { + if ((*it)->getUniqueId() == uniqueId) + return (*it); + } + + return 0; +} + +PluginIterator +AudioPluginManager::begin() +{ + awaitEnumeration(); + return m_plugins.begin(); +} + +PluginIterator +AudioPluginManager::end() +{ + awaitEnumeration(); + return m_plugins.end(); +} + +void +AudioPluginManager::awaitEnumeration() +{ + while (!m_enumerator.isDone()) { + RG_DEBUG << "\n\nAudioPluginManager::awaitEnumeration() - waiting\n\n" << endl; +// m_mutex.lock(); + usleep(100000); +// m_mutex.unlock(); + } +} + +void +AudioPluginManager::fetchSampleRate() +{ + QCString replyType; + QByteArray replyData; + + if (rgapp->sequencerCall("getSampleRate()", replyType, replyData)) { + + QDataStream streamIn(replyData, IO_ReadOnly); + unsigned int result; + streamIn >> result; + m_sampleRate = result; + } +} + +} diff --git a/src/gui/studio/AudioPluginManager.h b/src/gui/studio/AudioPluginManager.h new file mode 100644 index 0000000..f8574f8 --- /dev/null +++ b/src/gui/studio/AudioPluginManager.h @@ -0,0 +1,118 @@ + +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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. +*/ + +#ifndef _RG_AUDIOPLUGINMANAGER_H_ +#define _RG_AUDIOPLUGINMANAGER_H_ + +#include "AudioPluginClipboard.h" +#include +#include +#include +#include +#include "AudioPlugin.h" + + + + +namespace Rosegarden +{ + +class AudioPlugin; + + +class AudioPluginManager +{ +public: + AudioPluginManager(); + + // Get a straight list of names + // + std::vector getPluginNames(); + + // Some useful members + // + AudioPlugin* getPlugin(int number); + + AudioPlugin* getPluginByIdentifier(QString identifier); + int getPositionByIdentifier(QString identifier); + + // Deprecated -- the GUI shouldn't be using unique ID because it's + // bound to a particular plugin type (and not necessarily unique + // anyway). It should use the identifier instead, which is a + // structured string managed by the sequencer. Keep this in only + // for compatibility with old .rg files. + // + AudioPlugin* getPluginByUniqueId(unsigned long uniqueId); + + PluginIterator begin(); + PluginIterator end(); + + // Sample rate + // + void setSampleRate(unsigned int rate) { m_sampleRate = rate; } + unsigned int getSampleRate() const { return m_sampleRate; } + + AudioPluginClipboard* getPluginClipboard() { return &m_pluginClipboard; } + +protected: + AudioPlugin* addPlugin(const QString &identifier, + const QString &name, + unsigned long uniqueId, + const QString &label, + const QString &author, + const QString ©right, + bool isSynth, + bool isGrouped, + const QString &category); + + bool removePlugin(const QString &identifier); + + class Enumerator : public QThread + { + public: + Enumerator(AudioPluginManager *); + virtual void run(); + bool isDone() const { return m_done; } + + protected: + AudioPluginManager *m_manager; + bool m_done; + }; + + void awaitEnumeration(); + void fetchSampleRate(); + + std::vector m_plugins; + unsigned int m_sampleRate; + AudioPluginClipboard m_pluginClipboard; + Enumerator m_enumerator; + QMutex m_mutex; +}; + + + +} + +#endif diff --git a/src/gui/studio/AudioPluginOSCGUI.cpp b/src/gui/studio/AudioPluginOSCGUI.cpp new file mode 100644 index 0000000..106cbbe --- /dev/null +++ b/src/gui/studio/AudioPluginOSCGUI.cpp @@ -0,0 +1,234 @@ +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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. +*/ + +#ifdef HAVE_LIBLO + +#include "AudioPluginOSCGUI.h" + +#include "misc/Debug.h" +#include "misc/Strings.h" +#include "base/AudioPluginInstance.h" +#include "base/Exception.h" +#include "sound/PluginIdentifier.h" +#include +#include +#include +#include +#include + + +namespace Rosegarden +{ + +AudioPluginOSCGUI::AudioPluginOSCGUI(AudioPluginInstance *instance, + QString serverURL, QString friendlyName) : + m_gui(0), + m_address(0), + m_basePath(""), + m_serverUrl(serverURL) +{ + QString identifier = strtoqstr(instance->getIdentifier()); + + QString filePath = getGUIFilePath(identifier); + if (!filePath) { + throw Exception("No GUI found"); + } + + QString type, soName, label; + PluginIdentifier::parseIdentifier(identifier, type, soName, label); + QFileInfo soInfo(soName); + + // arguments: osc url, dll name, label, instance tag + + m_gui = new KProcess(); + + *m_gui << filePath + << m_serverUrl + << soInfo.fileName() + << label + << friendlyName; + + RG_DEBUG << "AudioPluginOSCGUI::AudioPluginOSCGUI: Starting process " + << filePath << " " << m_serverUrl << " " + << soInfo.fileName() << " " << label << " " << friendlyName << endl; + + if (!m_gui->start(KProcess::NotifyOnExit, KProcess::NoCommunication)) { + RG_DEBUG << "AudioPluginOSCGUI::AudioPluginOSCGUI: Couldn't start process " << filePath << endl; + delete m_gui; + m_gui = 0; + throw Exception("Failed to start GUI"); + } +} + +AudioPluginOSCGUI::~AudioPluginOSCGUI() +{ + quit(); +} + +QString +AudioPluginOSCGUI::getGUIFilePath(QString identifier) +{ + QString type, soName, label; + PluginIdentifier::parseIdentifier(identifier, type, soName, label); + + RG_DEBUG << "AudioPluginOSCGUI::getGUIFilePath(" << identifier << ")" << endl; + + QFileInfo soInfo(soName); + if (soInfo.isRelative()) { + //!!! + RG_DEBUG << "AudioPluginOSCGUI::AudioPluginOSCGUI: Unable to deal with relative .so path \"" << soName << "\" in identifier \"" << identifier << "\" yet" << endl; + throw Exception("Can't deal with relative .soname"); + } + + QDir dir(soInfo.dir()); + QString fileBase(soInfo.baseName(TRUE)); + + if (!dir.cd(fileBase)) { + RG_DEBUG << "AudioPluginOSCGUI::AudioPluginOSCGUI: No GUI subdir for plugin .so " << soName << endl; + throw Exception("No GUI subdir available"); + } + + const QFileInfoList *list = dir.entryInfoList(); + + // in order of preference: + const char *suffixes[] = { "_rg", "_kde", "_qt", "_gtk2", "_gtk", "_x11", "_gui" + }; + int nsuffixes = sizeof(suffixes) / sizeof(suffixes[0]); + + for (int k = 0; k <= nsuffixes; ++k) { + + for (int fuzzy = 0; fuzzy <= 1; ++fuzzy) { + + QFileInfoListIterator i(*list); + QFileInfo *info; + + while ((info = i.current()) != 0) { + + RG_DEBUG << "Looking at " << info->fileName() << " in path " + << info->filePath() << " for suffix " << (k == nsuffixes ? "(none)" : suffixes[k]) << ", fuzzy " << fuzzy << endl; + + ++i; + + if (!(info->isFile() || info->isSymLink()) + || !info->isExecutable()) { + RG_DEBUG << "(not executable)" << endl; + continue; + } + + if (fuzzy) { + if (info->fileName().left(fileBase.length()) != fileBase) + continue; + RG_DEBUG << "(is file base)" << endl; + } else { + if (info->fileName().left(label.length()) != label) + continue; + RG_DEBUG << "(is label)" << endl; + } + + if (k == nsuffixes || info->fileName().lower().endsWith(suffixes[k])) { + RG_DEBUG << "(ends with suffix " << (k == nsuffixes ? "(none)" : suffixes[k]) << " or out of suffixes)" << endl; + return info->filePath(); + } + RG_DEBUG << "(doesn't end with suffix " << (k == nsuffixes ? "(none)" : suffixes[k]) << ")" << endl; + } + } + } + + return QString(); +} + +void +AudioPluginOSCGUI::setGUIUrl(QString url) +{ + if (m_address) + lo_address_free(m_address); + + char *host = lo_url_get_hostname(url); + char *port = lo_url_get_port(url); + m_address = lo_address_new(host, port); + free(host); + free(port); + + m_basePath = lo_url_get_path(url); +} + +void +AudioPluginOSCGUI::show() +{ + RG_DEBUG << "AudioPluginOSCGUI::show" << endl; + + if (!m_address) + return ; + QString path = m_basePath + "/show"; + lo_send(m_address, path, ""); +} + +void +AudioPluginOSCGUI::hide() +{ + if (!m_address) + return ; + QString path = m_basePath + "/hide"; + lo_send(m_address, path, ""); +} + +void +AudioPluginOSCGUI::quit() +{ + if (!m_address) + return ; + QString path = m_basePath + "/quit"; + lo_send(m_address, path, ""); +} + +void +AudioPluginOSCGUI::sendProgram(int bank, int program) +{ + if (!m_address) + return ; + QString path = m_basePath + "/program"; + lo_send(m_address, path, "ii", bank, program); +} + +void +AudioPluginOSCGUI::sendPortValue(int port, float value) +{ + if (!m_address) + return ; + QString path = m_basePath + "/control"; + lo_send(m_address, path, "if", port, value); +} + +void +AudioPluginOSCGUI::sendConfiguration(QString key, QString value) +{ + if (!m_address) + return ; + QString path = m_basePath + "/configure"; + lo_send(m_address, path, "ss", key.data(), value.data()); +} + +} + +#endif diff --git a/src/gui/studio/AudioPluginOSCGUI.h b/src/gui/studio/AudioPluginOSCGUI.h new file mode 100644 index 0000000..d1982f4 --- /dev/null +++ b/src/gui/studio/AudioPluginOSCGUI.h @@ -0,0 +1,77 @@ + +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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. +*/ + +#ifndef _RG_AUDIOPLUGINOSCGUI_H_ +#define _RG_AUDIOPLUGINOSCGUI_H_ + +#ifdef HAVE_LIBLO + +#include + +#include + + +class KProcess; + + +namespace Rosegarden +{ + +class AudioPluginInstance; + + +class AudioPluginOSCGUI +{ +public: + AudioPluginOSCGUI(AudioPluginInstance *instance, + QString serverURL, QString friendlyName); + virtual ~AudioPluginOSCGUI(); + + void setGUIUrl(QString url); + + void show(); + void hide(); + void quit(); + void sendProgram(int bank, int program); + void sendPortValue(int port, float value); + void sendConfiguration(QString key, QString value); + + static QString getGUIFilePath(QString identifier); + +protected: + KProcess *m_gui; + lo_address m_address; + QString m_basePath; + QString m_serverUrl; +}; + + + +} + + +#endif + +#endif diff --git a/src/gui/studio/AudioPluginOSCGUIManager.cpp b/src/gui/studio/AudioPluginOSCGUIManager.cpp new file mode 100644 index 0000000..54c23d7 --- /dev/null +++ b/src/gui/studio/AudioPluginOSCGUIManager.cpp @@ -0,0 +1,711 @@ +/* -*- 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 , + Chris Cannam , + Richard Bown + + 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. +*/ + +#ifdef HAVE_LIBLO + +#include + +#include "AudioPluginOSCGUIManager.h" + +#include "sound/Midi.h" +#include +#include "misc/Debug.h" +#include "misc/Strings.h" +#include "AudioPluginOSCGUI.h" +#include "base/AudioPluginInstance.h" +#include "base/Exception.h" +#include "base/Instrument.h" +#include "base/MidiProgram.h" +#include "base/RealTime.h" +#include "base/Studio.h" +#include "gui/application/RosegardenGUIApp.h" +#include "OSCMessage.h" +#include "sound/MappedEvent.h" +#include "sound/PluginIdentifier.h" +#include "StudioControl.h" +#include "TimerCallbackAssistant.h" +#include + + +namespace Rosegarden +{ + +static void osc_error(int num, const char *msg, const char *path) +{ + std::cerr << "Rosegarden: ERROR: liblo server error " << num + << " in path " << path << ": " << msg << std::endl; +} + +static int osc_message_handler(const char *path, const char *types, lo_arg **argv, + int argc, lo_message, void *user_data) +{ + AudioPluginOSCGUIManager *manager = (AudioPluginOSCGUIManager *)user_data; + + InstrumentId instrument; + int position; + QString method; + + if (!manager->parseOSCPath(path, instrument, position, method)) { + return 1; + } + + OSCMessage *message = new OSCMessage(); + message->setTarget(instrument); + message->setTargetData(position); + message->setMethod(qstrtostr(method)); + + int arg = 0; + while (types && arg < argc && types[arg]) { + message->addArg(types[arg], argv[arg]); + ++arg; + } + + manager->postMessage(message); + return 0; +} + +AudioPluginOSCGUIManager::AudioPluginOSCGUIManager(RosegardenGUIApp *app) : + m_app(app), + m_studio(0), + m_haveOSCThread(false), + m_oscBuffer(1023), + m_dispatchTimer(0) +{} + +AudioPluginOSCGUIManager::~AudioPluginOSCGUIManager() +{ + delete m_dispatchTimer; + + for (TargetGUIMap::iterator i = m_guis.begin(); i != m_guis.end(); ++i) { + for (IntGUIMap::iterator j = i->second.begin(); j != i->second.end(); + ++j) { + delete j->second; + } + } + m_guis.clear(); + +#ifdef HAVE_LIBLO_THREADSTOP + + if (m_haveOSCThread) + lo_server_thread_stop(m_serverThread); +#endif +} + +void +AudioPluginOSCGUIManager::checkOSCThread() +{ + if (m_haveOSCThread) + return ; + + m_serverThread = lo_server_thread_new(NULL, osc_error); + + lo_server_thread_add_method(m_serverThread, NULL, NULL, + osc_message_handler, this); + + lo_server_thread_start(m_serverThread); + + RG_DEBUG << "AudioPluginOSCGUIManager: Base OSC URL is " + << lo_server_thread_get_url(m_serverThread) << endl; + + m_dispatchTimer = new TimerCallbackAssistant(20, timerCallback, this); + + m_haveOSCThread = true; +} + +bool +AudioPluginOSCGUIManager::hasGUI(InstrumentId instrument, int position) +{ + PluginContainer *container = 0; + container = m_studio->getContainerById(instrument); + if (!container) return false; + + AudioPluginInstance *pluginInstance = container->getPlugin(position); + if (!pluginInstance) return false; + + try { + QString filePath = AudioPluginOSCGUI::getGUIFilePath + (strtoqstr(pluginInstance->getIdentifier())); + return (filePath && filePath != ""); + } catch (Exception e) { // that's OK + return false; + } +} + +void +AudioPluginOSCGUIManager::startGUI(InstrumentId instrument, int position) +{ + RG_DEBUG << "AudioPluginOSCGUIManager::startGUI: " << instrument << "," << position + << endl; + + checkOSCThread(); + + if (m_guis.find(instrument) != m_guis.end() && + m_guis[instrument].find(position) != m_guis[instrument].end()) { + RG_DEBUG << "stopping GUI first" << endl; + stopGUI(instrument, position); + } + + // check the label + PluginContainer *container = 0; + container = m_studio->getContainerById(instrument); + if (!container) { + RG_DEBUG << "AudioPluginOSCGUIManager::startGUI: no such instrument or buss as " + << instrument << endl; + return; + } + + AudioPluginInstance *pluginInstance = container->getPlugin(position); + if (!pluginInstance) { + RG_DEBUG << "AudioPluginOSCGUIManager::startGUI: no plugin at position " + << position << " for instrument " << instrument << endl; + return ; + } + + try { + AudioPluginOSCGUI *gui = + new AudioPluginOSCGUI(pluginInstance, + getOSCUrl(instrument, + position, + strtoqstr(pluginInstance->getIdentifier())), + getFriendlyName(instrument, + position, + strtoqstr(pluginInstance->getIdentifier()))); + m_guis[instrument][position] = gui; + + } catch (Exception e) { + + RG_DEBUG << "AudioPluginOSCGUIManager::startGUI: failed to start GUI: " + << e.getMessage() << endl; + } +} + +void +AudioPluginOSCGUIManager::showGUI(InstrumentId instrument, int position) +{ + RG_DEBUG << "AudioPluginOSCGUIManager::showGUI: " << instrument << "," << position + << endl; + + if (m_guis.find(instrument) != m_guis.end() && + m_guis[instrument].find(position) != m_guis[instrument].end()) { + m_guis[instrument][position]->show(); + } else { + startGUI(instrument, position); + } +} + +void +AudioPluginOSCGUIManager::stopGUI(InstrumentId instrument, int position) +{ + if (m_guis.find(instrument) != m_guis.end() && + m_guis[instrument].find(position) != m_guis[instrument].end()) { + delete m_guis[instrument][position]; + m_guis[instrument].erase(position); + if (m_guis[instrument].empty()) + m_guis.erase(instrument); + } +} + +void +AudioPluginOSCGUIManager::stopAllGUIs() +{ + while (!m_guis.empty()) { + while (!m_guis.begin()->second.empty()) { + delete (m_guis.begin()->second.begin()->second); + m_guis.begin()->second.erase(m_guis.begin()->second.begin()); + } + m_guis.erase(m_guis.begin()); + } +} + +void +AudioPluginOSCGUIManager::postMessage(OSCMessage *message) +{ + RG_DEBUG << "AudioPluginOSCGUIManager::postMessage" << endl; + m_oscBuffer.write(&message, 1); +} + +void +AudioPluginOSCGUIManager::updateProgram(InstrumentId instrument, int position) +{ + RG_DEBUG << "AudioPluginOSCGUIManager::updateProgram(" << instrument << "," + << position << ")" << endl; + + if (m_guis.find(instrument) == m_guis.end() || + m_guis[instrument].find(position) == m_guis[instrument].end()) + return ; + + PluginContainer *container = 0; + container = m_studio->getContainerById(instrument); + if (!container) return; + + AudioPluginInstance *pluginInstance = container->getPlugin(position); + if (!pluginInstance) return; + + unsigned long rv = StudioControl::getPluginProgram + (pluginInstance->getMappedId(), + strtoqstr(pluginInstance->getProgram())); + + int bank = rv >> 16; + int program = rv - (bank << 16); + + RG_DEBUG << "AudioPluginOSCGUIManager::updateProgram(" << instrument << "," + << position << "): rv " << rv << ", bank " << bank << ", program " << program << endl; + + m_guis[instrument][position]->sendProgram(bank, program); +} + +void +AudioPluginOSCGUIManager::updatePort(InstrumentId instrument, int position, + int port) +{ + RG_DEBUG << "AudioPluginOSCGUIManager::updatePort(" << instrument << "," + << position << "," << port << ")" << endl; + + if (m_guis.find(instrument) == m_guis.end() || + m_guis[instrument].find(position) == m_guis[instrument].end()) + return ; + + PluginContainer *container = 0; + container = m_studio->getContainerById(instrument); + if (!container) return; + + AudioPluginInstance *pluginInstance = container->getPlugin(position); + if (!pluginInstance) + return ; + + PluginPortInstance *porti = pluginInstance->getPort(port); + if (!porti) + return ; + + RG_DEBUG << "AudioPluginOSCGUIManager::updatePort(" << instrument << "," + << position << "," << port << "): value " << porti->value << endl; + + m_guis[instrument][position]->sendPortValue(port, porti->value); +} + +void +AudioPluginOSCGUIManager::updateConfiguration(InstrumentId instrument, int position, + QString key) +{ + RG_DEBUG << "AudioPluginOSCGUIManager::updateConfiguration(" << instrument << "," + << position << "," << key << ")" << endl; + + if (m_guis.find(instrument) == m_guis.end() || + m_guis[instrument].find(position) == m_guis[instrument].end()) + return ; + + PluginContainer *container = m_studio->getContainerById(instrument); + if (!container) return; + + AudioPluginInstance *pluginInstance = container->getPlugin(position); + if (!pluginInstance) return; + + QString value = strtoqstr(pluginInstance->getConfigurationValue(qstrtostr(key))); + + RG_DEBUG << "AudioPluginOSCGUIManager::updatePort(" << instrument << "," + << position << "," << key << "): value " << value << endl; + + m_guis[instrument][position]->sendConfiguration(key, value); +} + +QString +AudioPluginOSCGUIManager::getOSCUrl(InstrumentId instrument, int position, + QString identifier) +{ + // OSC URL will be of the form + // osc.udp://localhost:54343/plugin/dssi///