void MidiMixerWindow::slotFaderLevelChanged(float value) { const QObject *s = sender(); for (FaderVector::const_iterator it = m_faders.begin(); it != m_faders.end(); ++it) { if ((*it)->m_volumeFader == s) { Instrument *instr = m_studio-> getInstrumentById((*it)->m_id); if (instr) { instr->setControllerValue(MIDI_CONTROLLER_VOLUME, MidiByte(value)); if (instr->hasFixedChannel()) { // send out to external controllers as well if the // affected instrument is on a fixed channel. //!!! really want some notification of whether we have any! int tabIndex = m_tabWidget->currentIndex(); if (tabIndex < 0) tabIndex = 0; int i = 0; for (DeviceList::const_iterator dit = m_studio->begin(); dit != m_studio->end(); ++dit) { RG_DEBUG << "slotFaderLevelChanged: i = " << i << ", tabIndex " << tabIndex << endl; if (!dynamic_cast<MidiDevice*>(*dit)) continue; if (i != tabIndex) { ++i; continue; } RG_DEBUG << "slotFaderLevelChanged: device id = " << instr->getDevice()->getId() << ", visible device id " << (*dit)->getId() << endl; if (instr->getDevice()->getId() == (*dit)->getId()) { RG_DEBUG << "slotFaderLevelChanged: sending control device mapped event for channel " << instr->getNaturalChannel() << endl; MappedEvent mE((*it)->m_id, MappedEvent::MidiController, MIDI_CONTROLLER_VOLUME, MidiByte(value)); mE.setRecordedChannel(instr->getNaturalChannel()); mE.setRecordedDevice(Device::CONTROL_DEVICE); StudioControl::sendMappedEvent(mE); } break; } } } emit instrumentParametersChanged((*it)->m_id); return ; } } }
// Release the channel that thru MIDI events played on. // @author Tom Breton (Tehom) void TrackInfo::releaseThruChannel(Studio &studio) { if (!m_hasThruChannel) { return; } Instrument *instrument = studio.getInstrumentById(m_instrumentId); if (instrument && !m_useFixedChannel) { Device* device = instrument->getDevice(); Q_CHECK_PTR(device); AllocateChannels *allocator = device->getAllocator(); // Device is a channel-managing device (Midi), so release the // channel. if (allocator) { allocator->releaseThruChannel(m_thruChannel); } } // If we recently deleted a device, we may get a NULL instrument. // In that case, we can't actively release it but we don't need // to, we can just mark it released. else { /* if (!instrument || m_useFixedChannel) */ } m_thruChannel = -1; // Channel wants no setup if we somehow encounter it in this // state. m_isThruChannelReady = true; m_hasThruChannel = false; }
MappedInstrument::MappedInstrument(const Instrument &instr): m_type(instr.getType()), m_id(instr.getId()), m_name(instr.getName()), m_device((instr.getDevice())->getId()), m_audioChannels(instr.getAudioChannels()) {}
// Allocate a channel for thru MIDI events to play on. // @author Tom Breton (Tehom) void TrackInfo::allocateThruChannel(Studio &studio) { Instrument *instrument = studio.getInstrumentById(m_instrumentId); // If we have deleted a device, we may get a NULL instrument. In // that case, we can't do much. if (!instrument) { return; } // This value of fixity holds until releaseThruChannel is called. m_useFixedChannel = instrument->hasFixedChannel(); if (m_useFixedChannel) { m_thruChannel = instrument->getNaturalChannel(); m_hasThruChannel = true; m_isThruChannelReady = true; return; } Device* device = instrument->getDevice(); Q_CHECK_PTR(device); AllocateChannels *allocator = device->getAllocator(); #ifdef DEBUG_CONTROL_BLOCK RG_DEBUG << "TrackInfo::allocateThruChannel() " << (allocator ? "got an allocator" : "didn't get an allocator") << endl; #endif // Device is not a channel-managing device, so instrument's // natural channel is correct and requires no further setup. if (!allocator) { m_thruChannel = instrument->getNaturalChannel(); m_isThruChannelReady = true; m_hasThruChannel = true; return; } // Get a suitable channel. m_thruChannel = allocator->allocateThruChannel(*instrument); #ifdef DEBUG_CONTROL_BLOCK RG_DEBUG << "TrackInfo::allocateThruChannel() got channel" << (int)m_thruChannel << endl; #endif // Right now the channel is probably playing the wrong program. m_isThruChannelReady = false; m_hasThruChannel = true; }
void ControlRulerWidget::setSegments(RosegardenDocument *document, std::vector<Segment *> segments) { m_document = document; // m_segments = segments; // connect(m_document, SIGNAL(pointerPositionChanged(timeT)), // this, SLOT(slotPointerPositionChanged(timeT))); Composition &comp = document->getComposition(); Track *track = comp.getTrackById(segments[0]->getTrack()); Instrument *instr = document->getStudio(). getInstrumentById(track->getInstrument()); if (instr) { Device *device = instr->getDevice(); // Cast to a Controllable if possible, otherwise leave c NULL. Controllable *c = dynamic_cast<MidiDevice *>(device); if (!c) { c = dynamic_cast<SoftSynthDevice *>(device); } if (c) { m_controlList = &(c->getControlParameters()); } } SegmentSelection selection; selection.insert(segments.begin(), segments.end()); delete m_scale; setRulerScale(new SegmentsRulerScale(&m_document->getComposition(), selection, 0, Note(Note::Shortest).getDuration() / 2.0)); // This is single segment code setSegment(segments[0]); }
// Make the channel ready to play on. Send the program, etc. // @author Tom Breton (Tehom) void TrackInfo::makeChannelReady(Studio &studio) { #ifdef DEBUG_CONTROL_BLOCK RG_DEBUG << "TrackInfo::makeChannelReady()" << endl; #endif Instrument *instrument = studio.getInstrumentById(m_instrumentId); // If we have deleted a device, we may get a NULL instrument. In // that case, we can't do much. if (!instrument) { return; } // We can get non-Midi instruments here. There's nothing to do // for them. For fixed, sendChannelSetup is slightly wrong, but // could be adapted and parameterized by trackId. if ((instrument->getType() == Instrument::Midi) && !m_useFixedChannel) { // Re-acquire channel. It may change if instrument's program // became percussion or became non-percussion. Device* device = instrument->getDevice(); Q_CHECK_PTR(device); AllocateChannels *allocator = device->getAllocator(); if (allocator) { m_thruChannel = allocator->reallocateThruChannel(*instrument, m_thruChannel); // If somehow we got here without having a channel, we // have one now. m_hasThruChannel = true; #ifdef DEBUG_CONTROL_BLOCK RG_DEBUG << "TrackInfo::makeChannelReady() now has channel" << m_hasThruChannel << endl; #endif } // This is how Midi instrument readies a fixed channel. StudioControl::sendChannelSetup(instrument, m_thruChannel); } m_isThruChannelReady = true; }
void ModifyDeviceMappingCommand::execute() { Composition::trackcontainer &tracks = m_composition->getTracks(); Composition::trackcontainer::iterator it = tracks.begin(); Instrument *instr = 0; int index = 0; for (; it != tracks.end(); ++it) { instr = m_studio->getInstrumentById(it->second->getInstrument()); if (!instr || !instr->getDevice()) continue; if (instr->getDevice()->getId() == m_fromDevice) { // if source and target are MIDI if (m_studio->getDevice(m_fromDevice)->getType() == Device::Midi && m_studio->getDevice(m_toDevice)->getType() == Device::Midi) { // Try to match channels on the target device // MidiByte channel = instr->getNaturalChannel(); InstrumentList destList = m_studio-> getDevice(m_toDevice)->getPresentationInstruments(); InstrumentList::iterator dIt = destList.begin(); for (; dIt != destList.end(); ++dIt) { if ((*dIt)->getNaturalChannel() == channel) { break; } } // Failure to match anything and there's no Instruments // at all in the destination. Skip to next source Instrument. // if (dIt == destList.end() || destList.size() == 0) continue; RG_DEBUG << " Track " << it->first << ", setting Instrument to " << (*dIt)->getId() << endl; // store "to" and "from" values // m_mapping.push_back( std::pair < TrackId, InstrumentId > (it->first, instr->getId())); it->second->setInstrument((*dIt)->getId()); } else // audio is involved in the mapping - use indexes { // assign by index numbers InstrumentList destList = m_studio-> getDevice(m_toDevice)->getPresentationInstruments(); // skip if we can't match // if (index > (int)(destList.size() - 1)) continue; m_mapping.push_back( std::pair < TrackId, InstrumentId > (it->first, instr->getId())); it->second->setInstrument(destList[index]->getId()); } index++; } } }
void MidiMixerWindow::slotControllerChanged(float value) { const QObject *s = sender(); size_t i = 0, j = 0; for (i = 0; i < m_faders.size(); ++i) { for (j = 0; j < m_faders[i]->m_controllerRotaries.size(); ++j) { if (m_faders[i]->m_controllerRotaries[j].second == s) break; } // break out on match if (j != m_faders[i]->m_controllerRotaries.size()) break; } // Don't do anything if we've not matched and got solid values // for i and j // if (i == m_faders.size() || j == m_faders[i]->m_controllerRotaries.size()) return ; //RG_DEBUG << "MidiMixerWindow::slotControllerChanged - found a controller" //<< endl; Instrument *instr = m_studio->getInstrumentById( m_faders[i]->m_id); if (instr) { //RG_DEBUG << "MidiMixerWindow::slotControllerChanged - " //<< "got instrument to change" << endl; instr->setControllerValue(m_faders[i]-> m_controllerRotaries[j].first, MidiByte(value)); if (instr->hasFixedChannel()) { int tabIndex = m_tabWidget->currentIndex(); if (tabIndex < 0) tabIndex = 0; int k = 0; for (DeviceList::const_iterator dit = m_studio->begin(); dit != m_studio->end(); ++dit) { RG_DEBUG << "slotControllerChanged: k = " << k << ", tabIndex " << tabIndex << endl; if (!dynamic_cast<MidiDevice*>(*dit)) continue; if (k != tabIndex) { ++k; continue; } RG_DEBUG << "slotControllerChanged: device id = " << instr->getDevice()->getId() << ", visible device id " << (*dit)->getId() << endl; if (instr->getDevice()->getId() == (*dit)->getId()) { RG_DEBUG << "slotControllerChanged: sending control device mapped event for channel " << instr->getNaturalChannel() << endl; // send out to external controllers as well. //!!! really want some notification of whether we have any! MappedEvent mE(m_faders[i]->m_id, MappedEvent::MidiController, m_faders[i]->m_controllerRotaries[j].first, MidiByte(value)); mE.setRecordedChannel(instr->getNaturalChannel()); mE.setRecordedDevice(Device::CONTROL_DEVICE); StudioControl::sendMappedEvent(mE); } } } emit instrumentParametersChanged(m_faders[i]->m_id); } }
void TrackParameterBox::updateWidgets2() { Track *track = getTrack(); if (!track) return; Instrument *instrument = m_doc->getStudio().getInstrumentFor(track); if (!instrument) return; // *** Track Label QString trackName = strtoqstr(track->getLabel()); if (trackName.isEmpty()) trackName = tr("<untitled>"); else trackName.truncate(20); const int trackNum = track->getPosition() + 1; m_trackLabel->setText(tr("[ Track %1 - %2 ]").arg(trackNum).arg(trackName)); // *** Playback parameters // Device updatePlaybackDevice(instrument->getDevice()->getId()); // Instrument updateInstrument(instrument); // Archive m_archive->setChecked(track->isArchived()); // If the current Instrument is an Audio Instrument... if (instrument->getInstrumentType() == Instrument::Audio) { // Hide irrelevant portions. m_recordingFiltersFrame->setVisible(false); m_staffExportOptionsFrame->setVisible(false); // In the Create segments with... frame, only the color combo is // useful for an Audio track. m_presetLabel->setVisible(false); m_preset->setVisible(false); m_load->setVisible(false); m_clefLabel->setVisible(false); m_clef->setVisible(false); m_transposeLabel->setVisible(false); m_transpose->setVisible(false); m_pitchLabel->setVisible(false); m_lowestLabel->setVisible(false); m_lowest->setVisible(false); m_highestLabel->setVisible(false); m_highest->setVisible(false); } else { // MIDI or soft synth // Show everything. m_recordingFiltersFrame->setVisible(true); m_staffExportOptionsFrame->setVisible(true); // Create segments with... frame m_presetLabel->setVisible(true); m_preset->setVisible(true); m_load->setVisible(true); m_clefLabel->setVisible(true); m_clef->setVisible(true); m_transposeLabel->setVisible(true); m_transpose->setVisible(true); m_pitchLabel->setVisible(true); m_lowestLabel->setVisible(true); m_lowest->setVisible(true); m_highestLabel->setVisible(true); m_highest->setVisible(true); } // *** Recording filters // Device updateRecordingDevice(track->getMidiInputDevice()); // Channel m_recordingChannel->setCurrentIndex((int)track->getMidiInputChannel() + 1); // Thru Routing m_thruRouting->setCurrentIndex((int)track->getThruRouting()); // *** Staff export options // Notation size m_notationSize->setCurrentIndex(track->getStaffSize()); // Bracket type m_bracketType->setCurrentIndex(track->getStaffBracket()); // *** Create segments with // Preset (Label) m_preset->setText(strtoqstr(track->getPresetLabel())); // Clef m_clef->setCurrentIndex(track->getClef()); // Transpose m_transpose->setCurrentIndex( m_transpose->findText(QString("%1").arg(track->getTranspose()))); // Pitch Lowest QSettings settings; settings.beginGroup(GeneralOptionsConfigGroup); const int octaveBase = settings.value("midipitchoctave", -2).toInt() ; settings.endGroup(); const bool includeOctave = false; const Pitch lowest(track->getLowestPlayable(), Accidentals::NoAccidental); // NOTE: this now uses a new, overloaded version of Pitch::getAsString() // that explicitly works with the key of C major, and does not allow the // calling code to specify how the accidentals should be written out. // // Separate the note letter from the octave to avoid undue burden on // translators having to retranslate the same thing but for a number // difference QString tmp = QObject::tr(lowest.getAsString(includeOctave, octaveBase).c_str(), "note name"); tmp += tr(" %1").arg(lowest.getOctave(octaveBase)); m_lowest->setText(tmp); // Pitch Highest const Pitch highest(track->getHighestPlayable(), Accidentals::NoAccidental); tmp = QObject::tr(highest.getAsString(includeOctave, octaveBase).c_str(), "note name"); tmp += tr(" %1").arg(highest.getOctave(octaveBase)); m_highest->setText(tmp); // Color // Note: We only update the combobox contents if there is an actual // change to the document's colors. See slotDocColoursChanged(). m_color->setCurrentIndex(track->getColor()); }
// ??? Break this stuff off into an InstrumentPopup class. This class is too // big. void TrackButtons::populateInstrumentPopup(Instrument *thisTrackInstr, QMenu* instrumentPopup) { // pixmaps for icons to show connection states as variously colored boxes // ??? Factor out the icon-related stuff to make this routine clearer. // getIcon(Instrument *) would be ideal, but might not be easy. // getIcon(Device *) would also be needed. static QPixmap connectedPixmap, unconnectedPixmap, connectedUsedPixmap, unconnectedUsedPixmap, connectedSelectedPixmap, unconnectedSelectedPixmap; static bool havePixmaps = false; if (!havePixmaps) { IconLoader il; connectedPixmap = il.loadPixmap("connected"); connectedUsedPixmap = il.loadPixmap("connected-used"); connectedSelectedPixmap = il.loadPixmap("connected-selected"); unconnectedPixmap = il.loadPixmap("unconnected"); unconnectedUsedPixmap = il.loadPixmap("unconnected-used"); unconnectedSelectedPixmap = il.loadPixmap("unconnected-selected"); havePixmaps = true; } Composition &comp = m_doc->getComposition(); // clear the popup instrumentPopup->clear(); QMenu *currentSubMenu = 0; // position index int count = 0; int currentDevId = -1; // Get the list Studio &studio = m_doc->getStudio(); InstrumentList list = studio.getPresentationInstruments(); // For each instrument for (InstrumentList::iterator it = list.begin(); it != list.end(); ++it) { if (!(*it)) continue; // sanity check // get the Localized instrument name, with the string hackery performed // in Instrument QString iname((*it)->getLocalizedPresentationName()); // translate the program name // // Note we are converting the string from std to Q back to std then to // C. This is obviously ridiculous, but the fact that we have programName // here at all makes me think it exists as some kind of necessary hack // to coax tr() into behaving nicely. I decided to change it as little // as possible to get it to compile, and not refactor this down to the // simplest way to call tr() on a C string. QString programName(strtoqstr((*it)->getProgramName())); programName = QObject::tr(programName.toStdString().c_str()); Device *device = (*it)->getDevice(); DeviceId devId = device->getId(); bool connectedIcon = false; // Determine the proper program name and whether it is connected if ((*it)->getType() == Instrument::SoftSynth) { programName = ""; AudioPluginInstance *plugin = (*it)->getPlugin(Instrument::SYNTH_PLUGIN_POSITION); if (plugin) { // we don't translate any plugin program names or other texts programName = strtoqstr(plugin->getDisplayName()); connectedIcon = (plugin->getIdentifier() != ""); } } else if ((*it)->getType() == Instrument::Audio) { connectedIcon = true; } else { QString conn = RosegardenSequencer::getInstance()-> getConnection(devId); connectedIcon = (conn != ""); } // These two are for selecting the correct icon to display. bool instrUsedByMe = false; bool instrUsedByAnyone = false; if (thisTrackInstr && thisTrackInstr->getId() == (*it)->getId()) { instrUsedByMe = true; instrUsedByAnyone = true; } // If we have switched to a new device, we'll create a new submenu if (devId != (DeviceId)(currentDevId)) { currentDevId = int(devId); // For selecting the correct icon to display. bool deviceUsedByAnyone = false; if (instrUsedByMe) deviceUsedByAnyone = true; else { for (Composition::trackcontainer::iterator tit = comp.getTracks().begin(); tit != comp.getTracks().end(); ++tit) { if (tit->second->getInstrument() == (*it)->getId()) { instrUsedByAnyone = true; deviceUsedByAnyone = true; break; } Instrument *instr = studio.getInstrumentById(tit->second->getInstrument()); if (instr && (instr->getDevice()->getId() == devId)) { deviceUsedByAnyone = true; } } } QIcon icon (connectedIcon ? (deviceUsedByAnyone ? connectedUsedPixmap : connectedPixmap) : (deviceUsedByAnyone ? unconnectedUsedPixmap : unconnectedPixmap)); // Create a submenu for this device QMenu *subMenu = new QMenu(instrumentPopup); subMenu->setMouseTracking(true); subMenu->setIcon(icon); // Not needed so long as AA_DontShowIconsInMenus is false. //subMenu->menuAction()->setIconVisibleInMenu(true); // Menu title QString deviceName = QObject::tr(device->getName().c_str()); subMenu->setTitle(deviceName); // QObject name subMenu->setObjectName(deviceName); // Add the submenu to the popup menu instrumentPopup->addMenu(subMenu); // Connect the submenu to slotInstrumentSelected() connect(subMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotInstrumentSelected(QAction*))); currentSubMenu = subMenu; } else if (!instrUsedByMe) {