Overhaul InstrumentInfo

* Remove unused direct calls into plugin
* Assume empty model to mean plugin-provided MIDNAM (!)

The route owned Instrument-Info is the central access point used
by the GUI for MIDI name lookups.

At this point in time, custom settings are saved/restored by the
GUI (MidiTimeAxisView). InstrumentInfo provides a volatile store
for MIDNAM mode and model.
This commit is contained in:
Robin Gareus 2020-04-01 06:53:26 +02:00
parent 26c6d3c4c9
commit 3b77472ac0
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
6 changed files with 161 additions and 343 deletions

View File

@ -19,8 +19,8 @@
#ifndef __ardour_instrument_info_h__
#define __ardour_instrument_info_h__
#include <string>
#include <stdint.h>
#include <string>
#include <boost/weak_ptr.hpp>
@ -28,13 +28,16 @@
#include "evoral/Parameter.h"
#include "midi++/libmidi_visibility.h"
#include "ardour/libardour_visibility.h"
#include "midi++/libmidi_visibility.h"
namespace MIDI {
namespace Name {
class ChannelNameSet;
class Patch;
class ValueNameList;
class MasterDeviceNames;
class ControlNameList;
typedef std::list<boost::shared_ptr<Patch> > PatchNameList;
}
}
@ -43,40 +46,44 @@ namespace ARDOUR {
class Processor;
class LIBARDOUR_API InstrumentInfo {
public:
InstrumentInfo();
~InstrumentInfo ();
class LIBARDOUR_API InstrumentInfo
{
public:
InstrumentInfo ();
~InstrumentInfo ();
void set_external_instrument (const std::string& model, const std::string& mode);
void set_internal_instrument (boost::shared_ptr<ARDOUR::Processor>);
void set_external_instrument (const std::string& model, const std::string& mode);
void set_internal_instrument (boost::shared_ptr<ARDOUR::Processor>);
std::string get_patch_name (uint16_t bank, uint8_t program, uint8_t channel) const;
std::string get_patch_name_without (uint16_t bank, uint8_t program, uint8_t channel) const;
std::string get_controller_name (Evoral::Parameter param) const;
std::string get_instrument_name () const;
std::string get_note_name (uint16_t bank, uint8_t program, uint8_t channel, uint8_t note) const;
boost::shared_ptr<MIDI::Name::ChannelNameSet> get_patches (uint8_t channel);
std::string get_patch_name (uint16_t bank, uint8_t program, uint8_t channel) const;
std::string get_patch_name_without (uint16_t bank, uint8_t program, uint8_t channel) const;
std::string get_controller_name (Evoral::Parameter param) const;
PBD::Signal0<void> Changed;
boost::shared_ptr<MIDI::Name::MasterDeviceNames> master_device_names () const;
static const MIDI::Name::PatchNameList& general_midi_patches();
boost::shared_ptr<MIDI::Name::ChannelNameSet> get_patches (uint8_t channel);
boost::shared_ptr<MIDI::Name::ControlNameList> control_name_list (uint8_t channel);
private:
std::string external_instrument_model;
std::string external_instrument_mode;
boost::shared_ptr<const MIDI::Name::ValueNameList> value_name_list_by_control (uint8_t channel, uint8_t number) const;
boost::weak_ptr<ARDOUR::Processor> internal_instrument;
PBD::Signal0<void> Changed;
boost::shared_ptr<MIDI::Name::ChannelNameSet> plugin_programs_to_channel_name_set (boost::shared_ptr<Processor> p);
std::string get_plugin_patch_name (boost::shared_ptr<ARDOUR::Processor>, uint16_t bank, uint8_t program, uint8_t channel) const;
std::string get_plugin_controller_name (boost::shared_ptr<ARDOUR::Processor>, Evoral::Parameter) const;
bool have_custom_plugin_info () const;
std::string get_patch_name (uint16_t bank, uint8_t program, uint8_t channel, bool with_extra) const;
static MIDI::Name::PatchNameList _gm_patches;
private:
std::string model () const;
std::string mode () const;
std::string get_patch_name (uint16_t bank, uint8_t program, uint8_t channel, bool with_extra) const;
std::string external_instrument_model;
std::string external_instrument_mode;
boost::weak_ptr<ARDOUR::Processor> internal_instrument;
};
} /* namespace ARDOUR */
}
#endif /* __ardour_instrument_info_h__ */

View File

@ -250,26 +250,6 @@ public:
std::vector<PresetRecord> get_presets ();
/** @return true if this plugin will respond to MIDI program
* change messages by changing presets.
*
* This is hard to return a correct value for because most plugin APIs
* do not specify plugin behaviour. However, if you want to force
* the display of plugin built-in preset names rather than MIDI program
* numbers, return true. If you want a generic description, return
* false.
*/
virtual bool presets_are_MIDI_programs () const { return false; }
/** @return true if this plugin is General MIDI compliant, false
* otherwise.
*
* It is important to note that it is is almost impossible for a host
* (e.g. Ardour) to determine this for just about any plugin API
* known as of June 2012
*/
virtual bool current_preset_uses_general_midi () const { return false; }
/** @return Last preset to be requested; the settings may have
* been changed since; find out with parameter_changed_since_last_preset.
*/

View File

@ -26,9 +26,9 @@
#include "ardour/instrument_info.h"
#include "ardour/midi_patch_manager.h"
#include "ardour/processor.h"
#include "ardour/plugin.h"
#include "ardour/plugin_insert.h"
#include "ardour/processor.h"
#include "ardour/rc_configuration.h"
#include "pbd/i18n.h"
@ -37,8 +37,6 @@ using namespace ARDOUR;
using namespace MIDI::Name;
using std::string;
MIDI::Name::PatchNameList InstrumentInfo::_gm_patches;
InstrumentInfo::InstrumentInfo ()
: external_instrument_model (_("Unknown"))
{
@ -51,63 +49,139 @@ InstrumentInfo::~InstrumentInfo ()
void
InstrumentInfo::set_external_instrument (const string& model, const string& mode)
{
if (external_instrument_model == model && external_instrument_mode == mode && internal_instrument.expired ()) {
if (external_instrument_model == model && external_instrument_mode == mode) {
//std::cerr << "InstrumentInfo::set_external_instrument '" << model << "' '" << mode << "' -- no change\n";
return;
}
//std::cerr << "InstrumentInfo::set_external_instrument '" << model << "' '" << mode << "'\n";
external_instrument_model = model;
external_instrument_mode = mode;
internal_instrument.reset ();
Changed(); /* EMIT SIGNAL */
external_instrument_mode = mode;
Changed (); /* EMIT SIGNAL */
}
void
InstrumentInfo::set_internal_instrument (boost::shared_ptr<Processor> p)
{
bool changed = !external_instrument_mode.empty ();
external_instrument_mode = "";
if (p == internal_instrument.lock ()) {
//std::cerr << "InstrumentInfo::set_internal_instrument -- NO CHANGE\n";
return;
}
//std::cerr << "InstrumentInfo::set_internal_instrument -> '" << (p ? p->name () : "(NULL)") << "'\n";
internal_instrument = p;
if (external_instrument_model.empty () || external_instrument_model == _("Unknown")) {
Changed (); /* EMIT SIGNAL */
}
}
boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(p);
bool
InstrumentInfo::have_custom_plugin_info () const
{
boost::shared_ptr<Processor> p = internal_instrument.lock ();
boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (p);
if (pi && pi->plugin ()->has_midnam ()) {
/* really back hack, following MidiTimeAxisView::model_changed()
*
* InstrumentInfo::get_plugin_patch_name() needs to be overhauled,
* it limits all PluginInsert to generic-midi or only numbers.
*/
changed |= !internal_instrument.expired ();
changed |= external_instrument_model != pi->plugin ()->midnam_model ();
internal_instrument.reset ();
external_instrument_model = pi->plugin ()->midnam_model ();
const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance().custom_device_mode_names_by_model (external_instrument_model);
if (device_modes.size() > 0) {
changed |= external_instrument_mode != device_modes.front();
external_instrument_mode = device_modes.front();
std::string model = pi->plugin ()->midnam_model ();
const std::list<std::string> device_modes = MidiPatchManager::instance ().custom_device_mode_names_by_model (model);
if (device_modes.size () > 0) {
return true;
}
} else {
changed |= internal_instrument.lock () != p || external_instrument_model != _("Unknown");
internal_instrument = p;
external_instrument_model = _("Unknown");
}
if (changed) {
Changed(); /* EMIT SIGNAL */
return false;
}
std::string
InstrumentInfo::model () const
{
if (!external_instrument_model.empty ()) {
return external_instrument_model;
}
// TODO: cache plugin model
boost::shared_ptr<Processor> p = internal_instrument.lock ();
boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (p);
if (pi && pi->plugin ()->has_midnam ()) {
return pi->plugin ()->midnam_model ();
}
return "";
}
std::string
InstrumentInfo::mode () const
{
if (!external_instrument_model.empty ()) {
return external_instrument_mode;
}
// TODO: cache plugin mode
boost::shared_ptr<Processor> p = internal_instrument.lock ();
boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (p);
if (pi && pi->plugin ()->has_midnam ()) {
const std::list<std::string> device_modes = MidiPatchManager::instance ().custom_device_mode_names_by_model (model ());
if (device_modes.size () > 0) {
return device_modes.front ();
}
}
return "";
}
string
InstrumentInfo::get_instrument_name () const
InstrumentInfo::get_note_name (uint16_t bank, uint8_t program, uint8_t channel, uint8_t note) const
{
boost::shared_ptr<Processor> p = internal_instrument.lock();
if (p) {
return p->name();
}
if (external_instrument_mode.empty()) {
return external_instrument_model;
} else {
return string_compose ("%1 (%2)", external_instrument_model, external_instrument_mode);
boost::shared_ptr<MasterDeviceNames> const& dev_names (MidiPatchManager::instance ().master_device_by_model (model ()));
if (dev_names) {
return dev_names->note_name (mode (), channel, bank, program, note);
}
return "";
}
boost::shared_ptr<const ValueNameList>
InstrumentInfo::value_name_list_by_control (uint8_t channel, uint8_t number) const
{
boost::shared_ptr<MasterDeviceNames> const& dev_names (MidiPatchManager::instance ().master_device_by_model (model ()));
if (dev_names) {
return dev_names->value_name_list_by_control (mode (), channel, number);
}
return boost::shared_ptr<const ValueNameList> ();
}
boost::shared_ptr<MasterDeviceNames>
InstrumentInfo::master_device_names () const
{
#if 1
/* this safe if model does not exist */
boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance ().document_by_model (model ());
if (midnam) {
return midnam->master_device_names (model ());
}
return boost::shared_ptr<MasterDeviceNames> ();
#else
return MidiPatchManager::instance ().master_device_by_model (model ());
#endif
}
boost::shared_ptr<ControlNameList>
InstrumentInfo::control_name_list (uint8_t channel)
{
boost::shared_ptr<MasterDeviceNames> const& dev_names (MidiPatchManager::instance ().master_device_by_model (model ()));
boost::shared_ptr<ChannelNameSet> const& chan_names (dev_names->channel_name_set_by_channel (mode (), channel));
if (!chan_names) {
return boost::shared_ptr<ControlNameList> ();
}
return dev_names->control_name_list (chan_names->control_list_name ());
}
#if 0
MasterDeviceNames::ControlNameLists const&
InstrumentInfo::master_control_names () const
{
static MasterDeviceNames::ControlNameLists empty_list;
boost::shared_ptr<MasterDeviceNames> const& dev_names (MidiPatchManager::instance ().master_device_by_model (model ()));
if (dev_names) {
return dev_names->controls();
}
return empty_list;
}
#endif
string
InstrumentInfo::get_patch_name (uint16_t bank, uint8_t program, uint8_t channel) const
{
@ -123,26 +197,19 @@ InstrumentInfo::get_patch_name_without (uint16_t bank, uint8_t program, uint8_t
string
InstrumentInfo::get_patch_name (uint16_t bank, uint8_t program, uint8_t channel, bool with_extra) const
{
boost::shared_ptr<Processor> p = internal_instrument.lock();
if (p) {
return get_plugin_patch_name (p, bank, program, channel);
}
PatchPrimaryKey patch_key (program, bank);
MIDI::Name::PatchPrimaryKey patch_key (program, bank);
boost::shared_ptr<MIDI::Name::Patch> patch =
MIDI::Name::MidiPatchManager::instance().find_patch (external_instrument_model,
external_instrument_mode, channel, patch_key);
boost::shared_ptr<MIDI::Name::Patch> const& patch (MidiPatchManager::instance ().find_patch (model (), mode (), channel, patch_key));
if (patch) {
return patch->name();
return patch->name ();
} else {
/* program and bank numbers are zero-based: convert to one-based: MIDI_BP_ZERO */
#define MIDI_BP_ZERO ((Config->get_first_midi_bank_is_zero())?0:1)
#define MIDI_BP_ZERO ((Config->get_first_midi_bank_is_zero ()) ? 0 : 1)
if (with_extra) {
return string_compose ("prg %1 bnk %2",program + MIDI_BP_ZERO , bank + MIDI_BP_ZERO);
return string_compose ("prg %1 bnk %2", program + MIDI_BP_ZERO, bank + MIDI_BP_ZERO);
} else {
return string_compose ("%1", program + MIDI_BP_ZERO);
}
@ -152,136 +219,35 @@ InstrumentInfo::get_patch_name (uint16_t bank, uint8_t program, uint8_t channel,
string
InstrumentInfo::get_controller_name (Evoral::Parameter param) const
{
boost::shared_ptr<Processor> p = internal_instrument.lock();
if (param.type() != MidiCCAutomation) {
if (param.type () != MidiCCAutomation) {
return "";
}
if (p) {
return get_plugin_controller_name (p, param);
}
boost::shared_ptr<MIDI::Name::MasterDeviceNames> dev_names(
MIDI::Name::MidiPatchManager::instance().master_device_by_model(
external_instrument_model));
boost::shared_ptr<MasterDeviceNames> const& dev_names (MidiPatchManager::instance ().master_device_by_model (model ()));
if (!dev_names) {
return "";
}
boost::shared_ptr<ChannelNameSet> chan_names(
dev_names->channel_name_set_by_channel(
external_instrument_mode, param.channel()));
boost::shared_ptr<ChannelNameSet> const& chan_names (dev_names->channel_name_set_by_channel (mode (), param.channel ()));
if (!chan_names) {
return "";
}
boost::shared_ptr<ControlNameList> control_names(
dev_names->control_name_list(chan_names->control_list_name()));
boost::shared_ptr<ControlNameList> const& control_names (dev_names->control_name_list (chan_names->control_list_name ()));
if (!control_names) {
return "";
}
boost::shared_ptr<const Control> c = control_names->control(param.id());
boost::shared_ptr<const Control> const& c = control_names->control (param.id ());
if (c) {
return string_compose(c->name() + " [%1]", int(param.channel()) + 1);
return string_compose (c->name () + " [%1]", int(param.channel ()) + 1);
}
return "";
}
boost::shared_ptr<MIDI::Name::ChannelNameSet>
boost::shared_ptr<ChannelNameSet>
InstrumentInfo::get_patches (uint8_t channel)
{
boost::shared_ptr<Processor> p = internal_instrument.lock();
if (p) {
return plugin_programs_to_channel_name_set (p);
}
boost::shared_ptr<MIDI::Name::ChannelNameSet> channel_name_set =
MidiPatchManager::instance().find_channel_name_set (external_instrument_model,
external_instrument_mode,
channel);
//std::cerr << "got channel name set with name '" << channel_name_set->name() << std::endl;
return channel_name_set;
}
boost::shared_ptr<MIDI::Name::ChannelNameSet>
InstrumentInfo::plugin_programs_to_channel_name_set (boost::shared_ptr<Processor> p)
{
PatchNameList patch_list;
boost::shared_ptr<PluginInsert> insert = boost::dynamic_pointer_cast<PluginInsert> (p);
if (!insert) {
return boost::shared_ptr<ChannelNameSet>();
}
boost::shared_ptr<Plugin> pp = insert->plugin();
if (pp->current_preset_uses_general_midi()) {
patch_list = InstrumentInfo::general_midi_patches ();
} else if (pp->presets_are_MIDI_programs()) {
std::vector<Plugin::PresetRecord> presets = pp->get_presets ();
std::vector<Plugin::PresetRecord>::iterator i;
int n;
for (n = 0, i = presets.begin(); i != presets.end(); ++i, ++n) {
if ((*i).valid) {
patch_list.push_back (boost::shared_ptr<Patch> (new Patch ((*i).label, n)));
} else {
patch_list.push_back (boost::shared_ptr<Patch> (new Patch (string_compose ("program %1", n), n)));
}
}
} else {
for (int n = 0; n < 127; ++n) {
patch_list.push_back (boost::shared_ptr<Patch> (new Patch (string_compose ("program %1", n), n)));
}
}
boost::shared_ptr<PatchBank> pb (new PatchBank (0, p->name()));
pb->set_patch_name_list (patch_list);
ChannelNameSet::PatchBanks patch_banks;
patch_banks.push_back (pb);
boost::shared_ptr<MIDI::Name::ChannelNameSet> cns (new ChannelNameSet);
cns->set_patch_banks (patch_banks);
return cns;
}
const MIDI::Name::PatchNameList&
InstrumentInfo::general_midi_patches()
{
if (_gm_patches.empty()) {
for (int n = 0; n < 128; n++) {
_gm_patches.push_back (boost::shared_ptr<Patch> (new Patch (general_midi_program_names[n], n)));
}
}
return _gm_patches;
}
string
InstrumentInfo::get_plugin_controller_name (boost::shared_ptr<ARDOUR::Processor>, Evoral::Parameter param) const
{
return "";
}
string
InstrumentInfo::get_plugin_patch_name (boost::shared_ptr<Processor> p, uint16_t bank, uint8_t program, uint8_t /*channel*/) const
{
boost::shared_ptr<PluginInsert> insert = boost::dynamic_pointer_cast<PluginInsert> (p);
if (insert) {
boost::shared_ptr<Plugin> pp = insert->plugin();
if (pp->current_preset_uses_general_midi()) {
return MIDI::Name::general_midi_program_names[std::min((uint8_t) 127,program)];
}
}
return string_compose (_("preset %1 (bank %2)"), (int) program, (int) bank);
return MidiPatchManager::instance ().find_channel_name_set (model (), mode (), channel);
}

View File

@ -1701,9 +1701,7 @@ void
Route::reset_instrument_info ()
{
boost::shared_ptr<Processor> instr = the_instrument();
if (instr) {
_instrument_info.set_internal_instrument (instr);
}
_instrument_info.set_internal_instrument (instr);
}
/** Caller must hold process lock */

View File

@ -498,8 +498,6 @@ private:
MasterDeviceNames::Models _all_models;
};
LIBMIDIPP_API extern const char* general_midi_program_names[128]; /* 0 .. 127 */
}
}

View File

@ -967,137 +967,6 @@ MIDINameDocument::master_device_names(const std::string& model)
return boost::shared_ptr<MasterDeviceNames>();
}
const char* general_midi_program_names[128] = {
"Acoustic Grand Piano",
"Bright Acoustic Piano",
"Electric Grand Piano",
"Honky-tonk Piano",
"Rhodes Piano",
"Chorused Piano",
"Harpsichord",
"Clavinet",
"Celesta",
"Glockenspiel",
"Music Box",
"Vibraphone",
"Marimba",
"Xylophone",
"Tubular Bells",
"Dulcimer",
"Hammond Organ",
"Percussive Organ",
"Rock Organ",
"Church Organ",
"Reed Organ",
"Accordion",
"Harmonica",
"Tango Accordion",
"Acoustic Guitar (nylon)",
"Acoustic Guitar (steel)",
"Electric Guitar (jazz)",
"Electric Guitar (clean)",
"Electric Guitar (muted)",
"Overdriven Guitar",
"Distortion Guitar",
"Guitar Harmonics",
"Acoustic Bass",
"Electric Bass (finger)",
"Electric Bass (pick)",
"Fretless Bass",
"Slap Bass 1",
"Slap Bass 2",
"Synth Bass 1",
"Synth Bass 2",
"Violin",
"Viola",
"Cello",
"Contrabass",
"Tremolo Strings",
"Pizzicato Strings",
"Orchestral Harp",
"Timpani",
"String Ensemble 1",
"String Ensemble 2",
"SynthStrings 1",
"SynthStrings 2",
"Choir Aahs",
"Voice Oohs",
"Synth Voice",
"Orchestra Hit",
"Trumpet",
"Trombone",
"Tuba",
"Muted Trumpet",
"French Horn",
"Brass Section",
"Synth Brass 1",
"Synth Brass 2",
"Soprano Sax",
"Alto Sax",
"Tenor Sax",
"Baritone Sax",
"Oboe",
"English Horn",
"Bassoon",
"Clarinet",
"Piccolo",
"Flute",
"Recorder",
"Pan Flute",
"Bottle Blow",
"Shakuhachi",
"Whistle",
"Ocarina",
"Lead 1 (square)",
"Lead 2 (sawtooth)",
"Lead 3 (calliope lead)",
"Lead 4 (chiff lead)",
"Lead 5 (charang)",
"Lead 6 (voice)",
"Lead 7 (fifths)",
"Lead 8 (bass + lead)",
"Pad 1 (new age)",
"Pad 2 (warm)",
"Pad 3 (polysynth)",
"Pad 4 (choir)",
"Pad 5 (bowed)",
"Pad 6 (metallic)",
"Pad 7 (halo)",
"Pad 8 (sweep)",
"FX 1 (rain)",
"FX 2 (soundtrack)",
"FX 3 (crystal)",
"FX 4 (atmosphere)",
"FX 5 (brightness)",
"FX 6 (goblins)",
"FX 7 (echoes)",
"FX 8 (sci-fi)",
"Sitar",
"Banjo",
"Shamisen",
"Koto",
"Kalimba",
"Bagpipe",
"Fiddle",
"Shanai",
"Tinkle Bell",
"Agogo",
"Steel Drums",
"Woodblock",
"Taiko Drum",
"Melodic Tom",
"Synth Drum",
"Reverse Cymbal",
"Guitar Fret Noise",
"Breath Noise",
"Seashore",
"Bird Tweet",
"Telephone Ring",
"Helicopter",
"Applause",
"Gunshot",
};
} //namespace Name
} //namespace MIDI