// -*- c-basic-offset: 4 -*- /* Rosegarden A sequencer and musical notation editor. This program is Copyright 2000-2008 Guillaume Laurent , Chris Cannam , Richard Bown The moral right of the authors to claim authorship of this work has been asserted. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #include #include "Studio.h" #include "MidiDevice.h" #include "AudioDevice.h" #include "Instrument.h" #include "Segment.h" #include "Track.h" #include "Composition.h" #if (__GNUC__ < 3) #include #define stringstream strstream #else #include #endif using std::cerr; using std::endl; namespace Rosegarden { Studio::Studio() : m_midiThruFilter(0), m_midiRecordFilter(0), m_mixerDisplayOptions(0), m_metronomeDevice(0) { // We _always_ have a buss with id zero, for the master out m_busses.push_back(new Buss(0)); // And we always create one audio record in m_recordIns.push_back(new RecordIn()); } Studio::~Studio() { DeviceListIterator dIt = m_devices.begin(); for (; dIt != m_devices.end(); ++dIt) delete(*dIt); m_devices.clear(); for (size_t i = 0; i < m_busses.size(); ++i) { delete m_busses[i]; } for (size_t i = 0; i < m_recordIns.size(); ++i) { delete m_recordIns[i]; } } void Studio::addDevice(const std::string &name, DeviceId id, Device::DeviceType type) { switch(type) { case Device::Midi: m_devices.push_back(new MidiDevice(id, name, MidiDevice::Play)); break; case Device::Audio: m_devices.push_back(new AudioDevice(id, name)); break; default: std::cerr << "Studio::addDevice() - unrecognised device" << endl; break; } } void Studio::addDevice(Device *device) { m_devices.push_back(device); } void Studio::removeDevice(DeviceId id) { DeviceListIterator it; for (it = m_devices.begin(); it != m_devices.end(); it++) { if ((*it)->getId() == id) { delete *it; m_devices.erase(it); return; } } } InstrumentList Studio::getAllInstruments() { InstrumentList list, subList; DeviceListIterator it; // Append lists // for (it = m_devices.begin(); it != m_devices.end(); it++) { // get sub list subList = (*it)->getAllInstruments(); // concetenate list.insert(list.end(), subList.begin(), subList.end()); } return list; } InstrumentList Studio::getPresentationInstruments() { InstrumentList list, subList; std::vector::iterator it; MidiDevice *midiDevice; // Append lists // for (it = m_devices.begin(); it != m_devices.end(); it++) { midiDevice = dynamic_cast(*it); if (midiDevice) { // skip read-only devices if (midiDevice->getDirection() == MidiDevice::Record) continue; } // get sub list subList = (*it)->getPresentationInstruments(); // concatenate list.insert(list.end(), subList.begin(), subList.end()); } return list; } Instrument* Studio::getInstrumentById(InstrumentId id) { std::vector::iterator it; InstrumentList list; InstrumentList::iterator iit; for (it = m_devices.begin(); it != m_devices.end(); it++) { list = (*it)->getAllInstruments(); for (iit = list.begin(); iit != list.end(); iit++) if ((*iit)->getId() == id) return (*iit); } return 0; } // From a user selection (from a "Presentation" list) return // the matching Instrument // Instrument* Studio::getInstrumentFromList(int index) { std::vector::iterator it; InstrumentList list; InstrumentList::iterator iit; int count = 0; for (it = m_devices.begin(); it != m_devices.end(); it++) { MidiDevice *midiDevice = dynamic_cast(*it); if (midiDevice) { // skip read-only devices if (midiDevice->getDirection() == MidiDevice::Record) continue; } list = (*it)->getPresentationInstruments(); for (iit = list.begin(); iit != list.end(); iit++) { if (count == index) return (*iit); count++; } } return 0; } Instrument * Studio::getInstrumentFor(Segment *segment) { if (!segment) return 0; if (!segment->getComposition()) return 0; TrackId tid = segment->getTrack(); Track *track = segment->getComposition()->getTrackById(tid); if (!track) return 0; return getInstrumentFor(track); } Instrument * Studio::getInstrumentFor(Track *track) { if (!track) return 0; InstrumentId iid = track->getInstrument(); return getInstrumentById(iid); } BussList Studio::getBusses() { return m_busses; } Buss * Studio::getBussById(BussId id) { for (BussList::iterator i = m_busses.begin(); i != m_busses.end(); ++i) { if ((*i)->getId() == id) return *i; } return 0; } void Studio::addBuss(Buss *buss) { m_busses.push_back(buss); } PluginContainer * Studio::getContainerById(InstrumentId id) { PluginContainer *pc = getInstrumentById(id); if (pc) return pc; else return getBussById(id); } RecordIn * Studio::getRecordIn(int number) { if (number >= 0 && number < int(m_recordIns.size())) return m_recordIns[number]; else return 0; } // Clear down the devices - the devices will clear down their // own Instruments. // void Studio::clear() { InstrumentList list; std::vector::iterator it; for (it = m_devices.begin(); it != m_devices.end(); it++) delete *it; m_devices.erase(m_devices.begin(), m_devices.end()); } std::string Studio::toXmlString() { return toXmlString(std::vector()); } std::string Studio::toXmlString(const std::vector &devices) { std::stringstream studio; studio << "" << endl << endl; studio << endl; InstrumentList list; // Get XML version of devices // if (devices.empty()) { // export all devices and busses for (DeviceListIterator it = m_devices.begin(); it != m_devices.end(); it++) { studio << (*it)->toXmlString() << endl << endl; } for (BussList::iterator it = m_busses.begin(); it != m_busses.end(); ++it) { studio << (*it)->toXmlString() << endl << endl; } } else { for (std::vector::const_iterator di(devices.begin()); di != devices.end(); ++di) { Device *d = getDevice(*di); if (!d) { std::cerr << "WARNING: Unknown device id " << (*di) << " in Studio::toXmlString" << std::endl; } else { studio << d->toXmlString() << endl << endl; } } } studio << endl << endl; #if (__GNUC__ < 3) studio << "" << endl << std::ends; #else studio << "" << endl; #endif return studio.str(); } // Run through the Devices checking for MidiDevices and // returning the first Metronome we come across // const MidiMetronome* Studio::getMetronomeFromDevice(DeviceId id) { std::vector::iterator it; MidiDevice *midiDevice; for (it = m_devices.begin(); it != m_devices.end(); it++) { midiDevice = dynamic_cast(*it); if (midiDevice && midiDevice->getId() == id && midiDevice->getMetronome()) { return midiDevice->getMetronome(); } } return 0; } // Scan all MIDI devices for available channels and map // them to a current program Instrument* Studio::assignMidiProgramToInstrument(MidiByte program, int msb, int lsb, bool percussion) { MidiDevice *midiDevice; std::vector::iterator it; Rosegarden::InstrumentList::iterator iit; Rosegarden::InstrumentList instList; // Instruments that we may return // Rosegarden::Instrument *newInstrument = 0; Rosegarden::Instrument *firstInstrument = 0; bool needBank = (msb >= 0 || lsb >= 0); if (needBank) { if (msb < 0) msb = 0; if (lsb < 0) lsb = 0; } // Pass one - search through all MIDI instruments looking for // a match that we can re-use. i.e. if we have a matching // Program Change then we can use this Instrument. // for (it = m_devices.begin(); it != m_devices.end(); it++) { midiDevice = dynamic_cast(*it); if (midiDevice && midiDevice->getDirection() == MidiDevice::Play) { instList = (*it)->getPresentationInstruments(); for (iit = instList.begin(); iit != instList.end(); iit++) { if (firstInstrument == 0) firstInstrument = *iit; // If we find an Instrument sending the right program already. // if ((*iit)->sendsProgramChange() && (*iit)->getProgramChange() == program && (!needBank || ((*iit)->sendsBankSelect() && (*iit)->getMSB() == msb && (*iit)->getLSB() == lsb && (*iit)->isPercussion() == percussion))) { return (*iit); } else { // Ignore the program change and use the percussion // flag. // if ((*iit)->isPercussion() && percussion) { return (*iit); } // Otherwise store the first Instrument for // possible use later. // if (newInstrument == 0 && (*iit)->sendsProgramChange() == false && (*iit)->sendsBankSelect() == false && (*iit)->isPercussion() == percussion) newInstrument = *iit; } } } } // Okay, if we've got this far and we have a new Instrument to use // then use it. // if (newInstrument != 0) { newInstrument->setSendProgramChange(true); newInstrument->setProgramChange(program); if (needBank) { newInstrument->setSendBankSelect(true); newInstrument->setPercussion(percussion); newInstrument->setMSB(msb); newInstrument->setLSB(lsb); } } else // Otherwise we just reuse the first Instrument we found newInstrument = firstInstrument; return newInstrument; } // Just make all of these Instruments available for automatic // assignment in the assignMidiProgramToInstrument() method // by invalidating the ProgramChange flag. // // This method sounds much more dramatic than it actually is - // it could probably do with a rename. // // void Studio::unassignAllInstruments() { MidiDevice *midiDevice; AudioDevice *audioDevice; std::vector::iterator it; Rosegarden::InstrumentList::iterator iit; Rosegarden::InstrumentList instList; int channel = 0; for (it = m_devices.begin(); it != m_devices.end(); it++) { midiDevice = dynamic_cast(*it); if (midiDevice) { instList = (*it)->getPresentationInstruments(); for (iit = instList.begin(); iit != instList.end(); iit++) { // Only for true MIDI Instruments - not System ones // if ((*iit)->getId() >= MidiInstrumentBase) { (*iit)->setSendBankSelect(false); (*iit)->setSendProgramChange(false); (*iit)->setMidiChannel(channel); channel = ( channel + 1 ) % 16; (*iit)->setSendPan(false); (*iit)->setSendVolume(false); (*iit)->setPan(MidiMidValue); (*iit)->setVolume(100); } } } else { audioDevice = dynamic_cast(*it); if (audioDevice) { instList = (*it)->getPresentationInstruments(); for (iit = instList.begin(); iit != instList.end(); iit++) (*iit)->emptyPlugins(); } } } } void Studio::clearMidiBanksAndPrograms() { MidiDevice *midiDevice; std::vector::iterator it; for (it = m_devices.begin(); it != m_devices.end(); it++) { midiDevice = dynamic_cast(*it); if (midiDevice) { midiDevice->clearProgramList(); midiDevice->clearBankList(); } } } void Studio::clearBusses() { for (size_t i = 0; i < m_busses.size(); ++i) { delete m_busses[i]; } m_busses.clear(); m_busses.push_back(new Buss(0)); } void Studio::clearRecordIns() { for (size_t i = 0; i < m_recordIns.size(); ++i) { delete m_recordIns[i]; } m_recordIns.clear(); m_recordIns.push_back(new RecordIn()); } Device* Studio::getDevice(DeviceId id) { //cerr << "Studio[" << this << "]::getDevice(" << id << ")... "; std::vector::iterator it; for (it = m_devices.begin(); it != m_devices.end(); it++) { // if (it != m_devices.begin()) cerr << ", "; // cerr << (*it)->getId(); if ((*it)->getId() == id) { //cerr << ". Found" << endl; return (*it); } } //cerr << ". Not found" << endl; return 0; } std::string Studio::getSegmentName(InstrumentId id) { MidiDevice *midiDevice; std::vector::iterator it; Rosegarden::InstrumentList::iterator iit; Rosegarden::InstrumentList instList; for (it = m_devices.begin(); it != m_devices.end(); it++) { midiDevice = dynamic_cast(*it); if (midiDevice) { instList = (*it)->getAllInstruments(); for (iit = instList.begin(); iit != instList.end(); iit++) { if ((*iit)->getId() == id) { if ((*iit)->sendsProgramChange()) { return (*iit)->getProgramName(); } else { return midiDevice->getName() + " " + (*iit)->getName(); } } } } } return std::string(""); } InstrumentId Studio::getAudioPreviewInstrument() { AudioDevice *audioDevice; std::vector::iterator it; for (it = m_devices.begin(); it != m_devices.end(); it++) { audioDevice = dynamic_cast(*it); // Just the first one will do - we can make this more // subtle if we need to later. // if (audioDevice) return audioDevice->getPreviewInstrument(); } // system instrument - won't accept audio return 0; } bool Studio::haveMidiDevices() const { Rosegarden::DeviceListConstIterator it = m_devices.begin(); for (; it != m_devices.end(); it++) { if ((*it)->getType() == Device::Midi) return true; } return false; } }