You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rosegarden/src/base/Studio.cpp

668 lines
15 KiB

/*
Rosegarden
A sequencer and musical notation editor.
This program is Copyright 2000-2008
Guillaume Laurent <glaurent@telegraph-road.org>,
Chris Cannam <cannam@all-day-breakfast.com>,
Richard Bown <bownie@bownie.com>
The moral right of the authors to claim authorship of this work
has been asserted.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
*/
#include <iostream>
#include <sstream>
#include "Studio.h"
#include "MidiDevice.h"
#include "AudioDevice.h"
#include "Instrument.h"
#include "Segment.h"
#include "Track.h"
#include "Composition.h"
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<Device*>::iterator it;
MidiDevice *midiDevice;
// Append lists
//
for (it = m_devices.begin(); it != m_devices.end(); it++)
{
midiDevice = dynamic_cast<MidiDevice*>(*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<Device*>::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<Device*>::iterator it;
InstrumentList list;
InstrumentList::iterator iit;
int count = 0;
for (it = m_devices.begin(); it != m_devices.end(); it++)
{
MidiDevice *midiDevice = dynamic_cast<MidiDevice*>(*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<Device*>::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<DeviceId>());
}
std::string
Studio::toXmlString(const std::vector<DeviceId> &devices)
{
std::stringstream studio;
studio << "<studio thrufilter=\"" << m_midiThruFilter
<< "\" recordfilter=\"" << m_midiRecordFilter
<< "\" audioinputpairs=\"" << m_recordIns.size()
<< "\" mixerdisplayoptions=\"" << m_mixerDisplayOptions
<< "\" metronomedevice=\"" << m_metronomeDevice
<< "\">" << 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<DeviceId>::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 << "</studio>" << endl << std::ends;
#else
studio << "</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<Device*>::iterator it;
MidiDevice *midiDevice;
for (it = m_devices.begin(); it != m_devices.end(); it++)
{
midiDevice = dynamic_cast<MidiDevice*>(*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<Device*>::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<MidiDevice*>(*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<Device*>::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<MidiDevice*>(*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<AudioDevice*>(*it);
if (audioDevice)
{
instList = (*it)->getPresentationInstruments();
for (iit = instList.begin(); iit != instList.end(); iit++)
(*iit)->emptyPlugins();
}
}
}
}
void
Studio::clearMidiBanksAndPrograms()
{
MidiDevice *midiDevice;
std::vector<Device*>::iterator it;
for (it = m_devices.begin(); it != m_devices.end(); it++)
{
midiDevice = dynamic_cast<MidiDevice*>(*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<Device*>::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<Device*>::iterator it;
Rosegarden::InstrumentList::iterator iit;
Rosegarden::InstrumentList instList;
for (it = m_devices.begin(); it != m_devices.end(); it++)
{
midiDevice = dynamic_cast<MidiDevice*>(*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<Device*>::iterator it;
for (it = m_devices.begin(); it != m_devices.end(); it++)
{
audioDevice = dynamic_cast<AudioDevice*>(*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;
}
}