summaryrefslogtreecommitdiffstats
path: root/src/base/Instrument.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/Instrument.cpp')
-rw-r--r--src/base/Instrument.cpp645
1 files changed, 645 insertions, 0 deletions
diff --git a/src/base/Instrument.cpp b/src/base/Instrument.cpp
new file mode 100644
index 0000000..add1767
--- /dev/null
+++ b/src/base/Instrument.cpp
@@ -0,0 +1,645 @@
+// -*- c-basic-offset: 4 -*-
+
+/*
+ Rosegarden
+ A sequencer and musical notation editor.
+
+ This program is Copyright 2000-2008
+ Guillaume Laurent <[email protected]>,
+ Chris Cannam <[email protected]>,
+ Richard Bown <[email protected]>
+
+ 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 <stdio.h>
+
+#include "Instrument.h"
+#include "MidiDevice.h"
+#include "AudioPluginInstance.h"
+#include "AudioLevel.h"
+
+#if (__GNUC__ < 3)
+#include <strstream>
+#define stringstream strstream
+#else
+#include <sstream>
+#endif
+
+
+namespace Rosegarden
+{
+
+const unsigned int PluginContainer::PLUGIN_COUNT = 5;
+
+PluginContainer::PluginContainer(bool havePlugins)
+{
+ if (havePlugins) {
+ // Add a number of plugin place holders (unassigned)
+ for (unsigned int i = 0; i < PLUGIN_COUNT; i++)
+ addPlugin(new AudioPluginInstance(i));
+ }
+}
+
+PluginContainer::~PluginContainer()
+{
+ clearPlugins();
+}
+
+void
+PluginContainer::addPlugin(AudioPluginInstance *instance)
+{
+ m_audioPlugins.push_back(instance);
+}
+
+bool
+PluginContainer::removePlugin(unsigned int position)
+{
+ PluginInstanceIterator it = m_audioPlugins.begin();
+
+ for (; it != m_audioPlugins.end(); it++)
+ {
+ if ((*it)->getPosition() == position)
+ {
+ delete (*it);
+ m_audioPlugins.erase(it);
+ return true;
+ }
+
+ }
+
+ return false;
+}
+
+void
+PluginContainer::clearPlugins()
+{
+ PluginInstanceIterator it = m_audioPlugins.begin();
+ for (; it != m_audioPlugins.end(); it++)
+ delete (*it);
+
+ m_audioPlugins.erase(m_audioPlugins.begin(), m_audioPlugins.end());
+}
+
+void
+PluginContainer::emptyPlugins()
+{
+ PluginInstanceIterator it = m_audioPlugins.begin();
+ for (; it != m_audioPlugins.end(); it++)
+ {
+ (*it)->setAssigned(false);
+ (*it)->setBypass(false);
+ (*it)->clearPorts();
+ }
+}
+
+
+// Get an instance for an index
+//
+AudioPluginInstance*
+PluginContainer::getPlugin(unsigned int position)
+{
+ PluginInstanceIterator it = m_audioPlugins.begin();
+ for (; it != m_audioPlugins.end(); it++)
+ {
+ if ((*it)->getPosition() == position)
+ return *it;
+ }
+
+ return 0;
+}
+
+
+const unsigned int Instrument::SYNTH_PLUGIN_POSITION = 999;
+
+
+Instrument::Instrument(InstrumentId id,
+ InstrumentType it,
+ const std::string &name,
+ Device *device):
+ PluginContainer(it == Audio || it == SoftSynth),
+ m_id(id),
+ m_name(name),
+ m_type(it),
+ m_channel(0),
+ //m_input_channel(-1),
+ m_transpose(MidiMidValue),
+ m_pan(MidiMidValue),
+ m_volume(100),
+ m_level(0.0),
+ m_recordLevel(0.0),
+ m_device(device),
+ m_sendBankSelect(false),
+ m_sendProgramChange(false),
+ m_sendPan(false),
+ m_sendVolume(false),
+ m_mappedId(0),
+ m_audioInput(1000),
+ m_audioInputChannel(0),
+ m_audioOutput(0)
+{
+ if (it == Audio || it == SoftSynth)
+ {
+ // In an audio instrument we use the m_channel attribute to
+ // hold the number of audio channels this Instrument uses -
+ // not the MIDI channel number. Default is 2 (stereo).
+ //
+ m_channel = 2;
+
+ m_pan = 100; // audio pan ranges from -100 to 100 but
+ // we store within an unsigned char as
+ // 0 to 200.
+ }
+
+ if (it == SoftSynth) {
+ addPlugin(new AudioPluginInstance(SYNTH_PLUGIN_POSITION));
+ }
+}
+
+Instrument::Instrument(InstrumentId id,
+ InstrumentType it,
+ const std::string &name,
+ MidiByte channel,
+ Device *device):
+ PluginContainer(it == Audio || it == SoftSynth),
+ m_id(id),
+ m_name(name),
+ m_type(it),
+ m_channel(channel),
+ //m_input_channel(-1),
+ m_transpose(MidiMidValue),
+ m_pan(MidiMidValue),
+ m_volume(100),
+ m_level(0.0),
+ m_recordLevel(0.0),
+ m_device(device),
+ m_sendBankSelect(false),
+ m_sendProgramChange(false),
+ m_sendPan(false),
+ m_sendVolume(false),
+ m_mappedId(0),
+ m_audioInput(1000),
+ m_audioInputChannel(0),
+ m_audioOutput(0)
+{
+ // Add a number of plugin place holders (unassigned)
+ //
+ if (it == Audio || it == SoftSynth)
+ {
+ // In an audio instrument we use the m_channel attribute to
+ // hold the number of audio channels this Instrument uses -
+ // not the MIDI channel number. Default is 2 (stereo).
+ //
+ m_channel = 2;
+
+ m_pan = 100; // audio pan ranges from -100 to 100 but
+ // we store within an unsigned char as
+
+ } else {
+/*
+ *
+ * Let's try getting rid of this default behavior, and replacing it with a
+ * change to the factory autoload instead, because this just doesn't work out
+ * very well, and it's fiddly trying to sort the overall behavior into something
+ * less quirky (dmm)
+ *
+ // Also defined in Midi.h but we don't use that - not here
+ // in the clean inner sanctum.
+ //
+ const MidiByte MIDI_PERCUSSION_CHANNEL = 9;
+ const MidiByte MIDI_EXTENDED_PERCUSSION_CHANNEL = 10;
+
+ if (m_channel == MIDI_PERCUSSION_CHANNEL ||
+ m_channel == MIDI_EXTENDED_PERCUSSION_CHANNEL) {
+ setPercussion(true);
+ }
+*/
+ }
+
+ if (it == SoftSynth) {
+ addPlugin(new AudioPluginInstance(SYNTH_PLUGIN_POSITION));
+ }
+}
+
+Instrument::Instrument(const Instrument &ins):
+ XmlExportable(),
+ PluginContainer(ins.getType() == Audio || ins.getType() == SoftSynth),
+ m_id(ins.getId()),
+ m_name(ins.getName()),
+ m_type(ins.getType()),
+ m_channel(ins.getMidiChannel()),
+ //m_input_channel(ins.getMidiInputChannel()),
+ m_program(ins.getProgram()),
+ m_transpose(ins.getMidiTranspose()),
+ m_pan(ins.getPan()),
+ m_volume(ins.getVolume()),
+ m_level(ins.getLevel()),
+ m_recordLevel(ins.getRecordLevel()),
+ m_device(ins.getDevice()),
+ m_sendBankSelect(ins.sendsBankSelect()),
+ m_sendProgramChange(ins.sendsProgramChange()),
+ m_sendPan(ins.sendsPan()),
+ m_sendVolume(ins.sendsVolume()),
+ m_mappedId(ins.getMappedId()),
+ m_audioInput(ins.m_audioInput),
+ m_audioInputChannel(ins.m_audioInputChannel),
+ m_audioOutput(ins.m_audioOutput)
+{
+ if (ins.getType() == Audio || ins.getType() == SoftSynth)
+ {
+ // In an audio instrument we use the m_channel attribute to
+ // hold the number of audio channels this Instrument uses -
+ // not the MIDI channel number. Default is 2 (stereo).
+ //
+ m_channel = 2;
+ }
+
+ if (ins.getType() == SoftSynth) {
+ addPlugin(new AudioPluginInstance(SYNTH_PLUGIN_POSITION));
+ }
+}
+
+Instrument &
+Instrument::operator=(const Instrument &ins)
+{
+ if (&ins == this) return *this;
+
+ m_id = ins.getId();
+ m_name = ins.getName();
+ m_type = ins.getType();
+ m_channel = ins.getMidiChannel();
+ //m_input_channel = ins.getMidiInputChannel();
+ m_program = ins.getProgram();
+ m_transpose = ins.getMidiTranspose();
+ m_pan = ins.getPan();
+ m_volume = ins.getVolume();
+ m_level = ins.getLevel();
+ m_recordLevel = ins.getRecordLevel();
+ m_device = ins.getDevice();
+ m_sendBankSelect = ins.sendsBankSelect();
+ m_sendProgramChange = ins.sendsProgramChange();
+ m_sendPan = ins.sendsPan();
+ m_sendVolume = ins.sendsVolume();
+ m_mappedId = ins.getMappedId();
+ m_audioInput = ins.m_audioInput;
+ m_audioInputChannel = ins.m_audioInputChannel;
+ m_audioOutput = ins.m_audioOutput;
+
+ return *this;
+}
+
+
+Instrument::~Instrument()
+{
+}
+
+std::string
+Instrument::getPresentationName() const
+{
+ if (m_type == Audio || m_type == SoftSynth || !m_device) {
+ return m_name;
+ } else {
+ return m_device->getName() + " " + m_name;
+ }
+}
+
+void
+Instrument::setProgramChange(MidiByte program)
+{
+ m_program = MidiProgram(m_program.getBank(), program);
+}
+
+MidiByte
+Instrument::getProgramChange() const
+{
+ return m_program.getProgram();
+}
+
+void
+Instrument::setMSB(MidiByte msb)
+{
+ m_program = MidiProgram(MidiBank(m_program.getBank().isPercussion(),
+ msb,
+ m_program.getBank().getLSB()),
+ m_program.getProgram());
+}
+
+MidiByte
+Instrument::getMSB() const
+{
+ return m_program.getBank().getMSB();
+}
+
+void
+Instrument::setLSB(MidiByte lsb)
+{
+ m_program = MidiProgram(MidiBank(m_program.getBank().isPercussion(),
+ m_program.getBank().getMSB(),
+ lsb),
+ m_program.getProgram());
+}
+
+MidiByte
+Instrument::getLSB() const
+{
+ return m_program.getBank().getLSB();
+}
+
+void
+Instrument::setPercussion(bool percussion)
+{
+ m_program = MidiProgram(MidiBank(percussion,
+ m_program.getBank().getMSB(),
+ m_program.getBank().getLSB()),
+ m_program.getProgram());
+}
+
+bool
+Instrument::isPercussion() const
+{
+ return m_program.getBank().isPercussion();
+}
+
+void
+Instrument::setAudioInputToBuss(BussId buss, int channel)
+{
+ m_audioInput = buss;
+ m_audioInputChannel = channel;
+}
+
+void
+Instrument::setAudioInputToRecord(int recordIn, int channel)
+{
+ m_audioInput = recordIn + 1000;
+ m_audioInputChannel = channel;
+}
+
+int
+Instrument::getAudioInput(bool &isBuss, int &channel) const
+{
+ channel = m_audioInputChannel;
+
+ if (m_audioInput >= 1000) {
+ isBuss = false;
+ return m_audioInput - 1000;
+ } else {
+ isBuss = true;
+ return m_audioInput;
+ }
+}
+
+
+// Implementation of the virtual method to output this class
+// as XML. We don't send out the name as it's redundant in
+// the file - that is driven from the sequencer.
+//
+//
+std::string
+Instrument::toXmlString()
+{
+
+ std::stringstream instrument;
+
+ // We don't send system Instruments out this way -
+ // only user Instruments.
+ //
+ if (m_id < AudioInstrumentBase)
+ {
+#if (__GNUC__ < 3)
+ instrument << std::ends;
+#endif
+ return instrument.str();
+ }
+
+ instrument << " <instrument id=\"" << m_id;
+ instrument << "\" channel=\"" << (int)m_channel;
+ instrument << "\" type=\"";
+
+ if (m_type == Midi)
+ {
+ instrument << "midi\">" << std::endl;
+
+ if (m_sendBankSelect)
+ {
+ instrument << " <bank percussion=\""
+ << (isPercussion() ? "true" : "false") << "\" msb=\""
+ << (int)getMSB();
+ instrument << "\" lsb=\"" << (int)getLSB() << "\"/>" << std::endl;
+ }
+
+ if (m_sendProgramChange)
+ {
+ instrument << " <program id=\""
+ << (int)getProgramChange() << "\"/>"
+ << std::endl;
+ }
+
+ instrument << " <pan value=\""
+ << (int)m_pan << "\"/>" << std::endl;
+
+ instrument << " <volume value=\""
+ << (int)m_volume << "\"/>" << std::endl;
+
+ for (StaticControllerConstIterator it = m_staticControllers.begin();
+ it != m_staticControllers.end(); ++it)
+ {
+ instrument << " <controlchange type=\"" << int(it->first)
+ << "\" value=\"" << int(it->second) << "\"/>" << std::endl;
+ }
+
+ }
+ else // Audio or SoftSynth
+ {
+
+ if (m_type == Audio) {
+ instrument << "audio\">" << std::endl;
+ } else {
+ instrument << "softsynth\">" << std::endl;
+ }
+
+ instrument << " <pan value=\""
+ << (int)m_pan << "\"/>" << std::endl;
+
+ instrument << " <level value=\""
+ << m_level << "\"/>" << std::endl;
+
+ instrument << " <recordLevel value=\""
+ << m_recordLevel << "\"/>" << std::endl;
+
+ bool aibuss;
+ int channel;
+ int ai = getAudioInput(aibuss, channel);
+
+ instrument << " <audioInput value=\""
+ << ai << "\" type=\""
+ << (aibuss ? "buss" : "record")
+ << "\" channel=\"" << channel
+ << "\"/>" << std::endl;
+
+ instrument << " <audioOutput value=\""
+ << m_audioOutput << "\"/>" << std::endl;
+
+ PluginInstanceIterator it = m_audioPlugins.begin();
+ for (; it != m_audioPlugins.end(); it++)
+ {
+ instrument << (*it)->toXmlString();
+ }
+ }
+
+ instrument << " </instrument>" << std::endl
+#if (__GNUC__ < 3)
+ << std::endl << std::ends;
+#else
+ << std::endl;
+#endif
+
+ return instrument.str();
+
+}
+
+
+// Return a program name given a bank select (and whether
+// we send it or not)
+//
+std::string
+Instrument::getProgramName() const
+{
+ if (m_sendProgramChange == false)
+ return std::string("");
+
+ MidiProgram program(m_program);
+
+ if (!m_sendBankSelect)
+ program = MidiProgram(MidiBank(isPercussion(), 0, 0), program.getProgram());
+
+ return ((dynamic_cast<MidiDevice*>(m_device))->getProgramName(program));
+}
+
+void
+Instrument::setControllerValue(MidiByte controller, MidiByte value)
+{
+ for (StaticControllerIterator it = m_staticControllers.begin();
+ it != m_staticControllers.end(); ++it)
+ {
+ if (it->first == controller)
+ {
+ it->second = value;
+ return;
+ }
+ }
+
+ m_staticControllers.push_back(std::pair<MidiByte, MidiByte>(controller, value));
+
+}
+
+MidiByte
+Instrument::getControllerValue(MidiByte controller) const
+{
+ for (StaticControllerConstIterator it = m_staticControllers.begin();
+ it != m_staticControllers.end(); ++it)
+ {
+
+ if (it->first == controller)
+ return it->second;
+ }
+
+ throw std::string("<no controller of that value>");
+}
+
+const MidiKeyMapping *
+Instrument::getKeyMapping() const
+{
+ MidiDevice *md = dynamic_cast<MidiDevice*>(m_device);
+ if (!md) return 0;
+
+ const MidiKeyMapping *mkm = md->getKeyMappingForProgram(m_program);
+ if (mkm) return mkm;
+
+ if (isPercussion()) { // if any key mapping is available, use it
+ const KeyMappingList &kml = md->getKeyMappings();
+ if (kml.begin() != kml.end()) {
+ return &(*kml.begin());
+ }
+ }
+
+ return 0;
+}
+
+
+Buss::Buss(BussId id) :
+ PluginContainer(true),
+ m_id(id),
+ m_level(0.0),
+ m_pan(100),
+ m_mappedId(0)
+{
+}
+
+Buss::~Buss()
+{
+}
+
+std::string
+Buss::toXmlString()
+{
+ std::stringstream buss;
+
+ buss << " <buss id=\"" << m_id << "\">" << std::endl;
+ buss << " <pan value=\"" << (int)m_pan << "\"/>" << std::endl;
+ buss << " <level value=\"" << m_level << "\"/>" << std::endl;
+
+ PluginInstanceIterator it = m_audioPlugins.begin();
+ for (; it != m_audioPlugins.end(); it++) {
+ buss << (*it)->toXmlString();
+ }
+
+ buss << " </buss>" << std::endl;
+
+#if (__GNUC__ < 3)
+ buss << std::ends;
+#endif
+
+ return buss.str();
+}
+
+std::string
+Buss::getName() const
+{
+ char buffer[20];
+ sprintf(buffer, "Submaster %d", m_id);
+ return buffer;
+}
+
+std::string
+Buss::getPresentationName() const
+{
+ return getName();
+}
+
+RecordIn::RecordIn() :
+ m_mappedId(0)
+{
+}
+
+RecordIn::~RecordIn()
+{
+}
+
+std::string
+RecordIn::toXmlString()
+{
+ // We don't actually save these, as they have nothing persistent
+ // in them. The studio just remembers how many there should be.
+ return "";
+}
+
+
+}
+