Pan automation/serialization fixes.
"Live" Midi CC sending from Midi CC automation track controllers. git-svn-id: svn://localhost/ardour2/trunk@2097 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
ef0b9a7409
commit
0da2977027
|
@ -336,13 +336,20 @@ AudioTimeAxisView::update_pans ()
|
|||
/* Man I hate that damn stereo->stereo panner */
|
||||
uint32_t i = 0;
|
||||
for (p = _route->panner().begin(); p != _route->panner().end(); ++p) {
|
||||
boost::shared_ptr<AutomationControl> pan_control = (*p)->pan_control();
|
||||
|
||||
if (pan_control->list()->param_id().type() == NullAutomation) {
|
||||
error << "Pan control has NULL automation type!" << endmsg;
|
||||
continue;
|
||||
}
|
||||
|
||||
boost::shared_ptr<AutomationTimeAxisView> pan_track(new AutomationTimeAxisView (_session,
|
||||
_route, _route/*FIXME*/, (*p)->pan_control(),
|
||||
_route, _route/*FIXME*/, pan_control,
|
||||
editor,
|
||||
*this,
|
||||
parent_canvas,
|
||||
_route->describe_parameter((*p)->pan_control()->list()->param_id()),
|
||||
ParamID(PanAutomation, i).to_string()/* FIXME: correct state name? */));
|
||||
_route->describe_parameter(pan_control->list()->param_id()),
|
||||
pan_control->list()->param_id().to_string()/* FIXME: correct state name? */));
|
||||
add_automation_child(ParamID(PanAutomation, i), pan_track);
|
||||
++i;
|
||||
}
|
||||
|
|
|
@ -75,7 +75,11 @@ void
|
|||
AutomationController::update_label(char* label, int label_len)
|
||||
{
|
||||
if (label && label_len)
|
||||
snprintf(label, label_len, "%.3f", _controllable->get_value());
|
||||
// Hack to display CC rounded to int
|
||||
if (_controllable->list()->param_id().type() == MidiCCAutomation)
|
||||
snprintf(label, label_len, "%d", (int)_controllable->get_value());
|
||||
else
|
||||
snprintf(label, label_len, "%.3f", _controllable->get_value());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -166,13 +166,20 @@ MidiTimeAxisView::build_automation_action_menu ()
|
|||
void
|
||||
MidiTimeAxisView::add_controller_track()
|
||||
{
|
||||
AddMidiCCTrackDialog dialog;
|
||||
dialog.set_transient_for(editor);
|
||||
int response = dialog.run();
|
||||
if (response == Gtk::RESPONSE_ACCEPT) {
|
||||
ParamID param = dialog.parameter();
|
||||
create_automation_child(param);
|
||||
int response;
|
||||
ParamID param;
|
||||
|
||||
{
|
||||
AddMidiCCTrackDialog dialog;
|
||||
dialog.set_transient_for(editor);
|
||||
response = dialog.run();
|
||||
|
||||
if (response == Gtk::RESPONSE_ACCEPT)
|
||||
param = dialog.parameter();
|
||||
}
|
||||
|
||||
if (response == Gtk::RESPONSE_ACCEPT)
|
||||
create_automation_child(param);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -182,11 +189,11 @@ MidiTimeAxisView::create_automation_child (ParamID param)
|
|||
|
||||
/* FIXME: this all probably leaks */
|
||||
|
||||
boost::shared_ptr<AutomationControl> c =_route->control(param);
|
||||
boost::shared_ptr<AutomationControl> c = _route->control(param);
|
||||
|
||||
if (!c) {
|
||||
boost::shared_ptr<AutomationList> al(new ARDOUR::AutomationList(param, 0, 127, 64));
|
||||
c = boost::shared_ptr<AutomationControl>(new AutomationControl(_session, al));
|
||||
c = boost::shared_ptr<AutomationControl>(new MidiTrack::MidiControl(midi_track(), al));
|
||||
_route->add_control(c);
|
||||
}
|
||||
|
||||
|
@ -197,6 +204,7 @@ MidiTimeAxisView::create_automation_child (ParamID param)
|
|||
parent_canvas,
|
||||
_route->describe_parameter(param),
|
||||
c->list()->param_id().to_string() /* FIXME: correct state name? */));
|
||||
|
||||
add_automation_child(param, track);
|
||||
|
||||
} else {
|
||||
|
|
|
@ -434,6 +434,9 @@ RouteTimeAxisView::build_automation_action_menu ()
|
|||
automation_items.push_back (MenuElem (_("Hide all automation"),
|
||||
mem_fun(*this, &RouteTimeAxisView::hide_all_automation)));
|
||||
|
||||
if (subplugin_menu.get_parent())
|
||||
subplugin_menu.detach();
|
||||
|
||||
automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu));
|
||||
|
||||
map<ARDOUR::ParamID, RouteAutomationNode*>::iterator i;
|
||||
|
@ -441,18 +444,16 @@ RouteTimeAxisView::build_automation_action_menu ()
|
|||
|
||||
automation_items.push_back (SeparatorElem());
|
||||
|
||||
if ( ! i->second->menu_item) {
|
||||
automation_items.push_back(CheckMenuElem (_route->describe_parameter(i->second->param),
|
||||
bind (mem_fun(*this, &RouteTimeAxisView::toggle_automation_track), i->second->param)));
|
||||
if (i->second->menu_item)
|
||||
delete i->second->menu_item;
|
||||
|
||||
i->second->menu_item = static_cast<Gtk::CheckMenuItem*>(&automation_items.back());
|
||||
automation_items.push_back(CheckMenuElem (_route->describe_parameter(i->second->param),
|
||||
bind (mem_fun(*this, &RouteTimeAxisView::toggle_automation_track), i->second->param)));
|
||||
|
||||
} else {
|
||||
automation_items.push_back (*i->second->menu_item);
|
||||
}
|
||||
|
||||
//i->second->menu_item->set_active(show_automation(i->second->param));
|
||||
i->second->menu_item->set_active(false);
|
||||
i->second->menu_item = static_cast<Gtk::CheckMenuItem*>(&automation_items.back());
|
||||
|
||||
i->second->menu_item->set_active(show_automation(i->second->param));
|
||||
//i->second->menu_item->set_active(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1796,6 +1797,8 @@ RouteTimeAxisView::add_automation_child(ParamID param, boost::shared_ptr<Automat
|
|||
_show_automation.insert(param);
|
||||
_route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
|
||||
}
|
||||
|
||||
build_display_menu();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -232,7 +232,7 @@ public:
|
|||
size_t write(double time, size_t size, const Byte* buf);
|
||||
bool read(double* time, size_t* size, Byte* buf);
|
||||
|
||||
size_t read(MidiBuffer& dst, nframes_t start, nframes_t end);
|
||||
size_t read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset=0);
|
||||
};
|
||||
|
||||
|
||||
|
@ -268,10 +268,10 @@ MidiRingBuffer::write(double time, size_t size, const Byte* buf)
|
|||
/** Read a block of MIDI events from buffer.
|
||||
*
|
||||
* Timestamps of events returned are relative to start (ie event with stamp 0
|
||||
* occurred at start).
|
||||
* occurred at start), with offset added.
|
||||
*/
|
||||
inline size_t
|
||||
MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end)
|
||||
MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t offset)
|
||||
{
|
||||
if (read_space() == 0)
|
||||
return 0;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define __ardour_midi_track_h__
|
||||
|
||||
#include <ardour/track.h>
|
||||
#include <ardour/midi_ring_buffer.h>
|
||||
|
||||
namespace ARDOUR
|
||||
{
|
||||
|
@ -71,6 +72,19 @@ public:
|
|||
|
||||
int set_state(const XMLNode& node);
|
||||
|
||||
bool write_immediate_event(size_t size, const Byte* buf);
|
||||
|
||||
struct MidiControl : public AutomationControl {
|
||||
MidiControl(boost::shared_ptr<MidiTrack> route, boost::shared_ptr<AutomationList> al)
|
||||
: AutomationControl (route->session(), al, al->param_id().to_string())
|
||||
, _route (route)
|
||||
{}
|
||||
|
||||
void set_value (float val);
|
||||
|
||||
boost::weak_ptr<MidiTrack> _route;
|
||||
};
|
||||
|
||||
protected:
|
||||
XMLNode& state (bool full);
|
||||
|
||||
|
@ -80,6 +94,8 @@ private:
|
|||
int set_diskstream (boost::shared_ptr<MidiDiskstream> ds);
|
||||
void set_state_part_two ();
|
||||
void set_state_part_three ();
|
||||
|
||||
MidiRingBuffer _immediate_events;
|
||||
};
|
||||
|
||||
} /* namespace ARDOUR*/
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define __ardour_panner_h__
|
||||
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
@ -106,7 +107,7 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful
|
|||
PanControllable (Session& s, std::string name, StreamPanner& p, ParamID param)
|
||||
: AutomationControl (s, boost::shared_ptr<AutomationList>(new AutomationList(
|
||||
param, 0.0, 1.0, 0.5)), name)
|
||||
, panner (p) {}
|
||||
, panner (p) { assert(param.type() != NullAutomation); }
|
||||
|
||||
StreamPanner& panner;
|
||||
|
||||
|
@ -124,7 +125,7 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful
|
|||
class BaseStereoPanner : public StreamPanner
|
||||
{
|
||||
public:
|
||||
BaseStereoPanner (Panner&);
|
||||
BaseStereoPanner (Panner&, ParamID param);
|
||||
~BaseStereoPanner ();
|
||||
|
||||
/* this class just leaves the pan law itself to be defined
|
||||
|
@ -151,7 +152,7 @@ class BaseStereoPanner : public StreamPanner
|
|||
class EqualPowerStereoPanner : public BaseStereoPanner
|
||||
{
|
||||
public:
|
||||
EqualPowerStereoPanner (Panner&);
|
||||
EqualPowerStereoPanner (Panner&, ParamID param);
|
||||
~EqualPowerStereoPanner ();
|
||||
|
||||
void distribute_automated (AudioBuffer& src, BufferSet& obufs,
|
||||
|
|
|
@ -55,8 +55,6 @@ public:
|
|||
ParamID(const std::string& str) : _type(NullAutomation), _id(0) {
|
||||
if (str == "gain") {
|
||||
_type = GainAutomation;
|
||||
} else if (str == "pan") {
|
||||
_type = PanAutomation;
|
||||
} else if (str == "solo") {
|
||||
_type = SoloAutomation;
|
||||
} else if (str == "mute") {
|
||||
|
@ -67,14 +65,17 @@ public:
|
|||
_type = FadeOutAutomation;
|
||||
} else if (str == "envelope") {
|
||||
_type = EnvelopeAutomation;
|
||||
} else if (str == "pan") {
|
||||
_type = PanAutomation;
|
||||
} else if (str.length() > 4 && str.substr(0, 4) == "pan-") {
|
||||
_type = PanAutomation;
|
||||
_id = atoi(str.c_str()+4);
|
||||
} else if (str.length() > 10 && str.substr(0, 10) == "parameter-") {
|
||||
_type = PluginAutomation;
|
||||
_id = atoi(str.c_str()+10);
|
||||
//PBD::info << "Parameter: " << str << " -> " << _id << endl;
|
||||
} else if (str.length() > 7 && str.substr(0, 7) == "midicc-") {
|
||||
_type = MidiCCAutomation;
|
||||
_id = atoi(str.c_str()+7);
|
||||
//PBD::info << "MIDI CC: " << str << " -> " << _id << endl;
|
||||
} else {
|
||||
PBD::warning << "Unknown ParamID '" << str << "'" << endmsg;
|
||||
}
|
||||
|
@ -119,6 +120,7 @@ public:
|
|||
} else if (_type == MidiCCAutomation) {
|
||||
return string_compose("midicc-%1", _id);
|
||||
} else {
|
||||
assert(false);
|
||||
PBD::warning << "Uninitialized ParamID to_string() called." << endmsg;
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -167,11 +167,11 @@ Automatable::control (ParamID parameter, bool create_if_missing)
|
|||
return i->second;
|
||||
|
||||
} else if (create_if_missing) {
|
||||
assert(parameter.type() != GainAutomation);
|
||||
boost::shared_ptr<AutomationList> al (new AutomationList (
|
||||
parameter, FLT_MIN, FLT_MAX, default_parameter_value (parameter)));
|
||||
boost::shared_ptr<AutomationControl> ac (new AutomationControl(_session, al));
|
||||
add_control(ac);
|
||||
cerr << "WARNING: Default AutomationControl created for " << parameter.to_string() << endl;
|
||||
return ac;
|
||||
|
||||
} else {
|
||||
|
|
|
@ -57,7 +57,7 @@ static void dumpit (const AutomationList& al, string prefix = "")
|
|||
AutomationList::AutomationList (ParamID id, double min_val, double max_val, double default_val)
|
||||
: _param_id(id)
|
||||
, _curve(new Curve(*this))
|
||||
{
|
||||
{
|
||||
_param_id = id;
|
||||
_frozen = 0;
|
||||
_changed_when_thawed = false;
|
||||
|
@ -73,7 +73,7 @@ AutomationList::AutomationList (ParamID id, double min_val, double max_val, doub
|
|||
_lookup_cache.range.first = _events.end();
|
||||
_sort_pending = false;
|
||||
|
||||
|
||||
assert(_param_id.type() != NullAutomation);
|
||||
AutomationListCreated(this);
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,7 @@ AutomationList::AutomationList (const AutomationList& other)
|
|||
}
|
||||
|
||||
mark_dirty ();
|
||||
assert(_param_id.type() != NullAutomation);
|
||||
AutomationListCreated(this);
|
||||
}
|
||||
|
||||
|
@ -135,6 +136,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
|
|||
|
||||
mark_dirty ();
|
||||
|
||||
assert(_param_id.type() != NullAutomation);
|
||||
AutomationListCreated(this);
|
||||
}
|
||||
|
||||
|
@ -162,6 +164,7 @@ AutomationList::AutomationList (const XMLNode& node, ParamID id)
|
|||
if (id)
|
||||
_param_id = id;
|
||||
|
||||
assert(_param_id.type() != NullAutomation);
|
||||
AutomationListCreated(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <ardour/utils.h>
|
||||
#include <ardour/buffer_set.h>
|
||||
#include <ardour/meter.h>
|
||||
#include <ardour/midi_events.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
|
@ -45,6 +46,7 @@ using namespace PBD;
|
|||
|
||||
MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mode)
|
||||
: Track (sess, name, flag, mode, DataType::MIDI)
|
||||
, _immediate_events(1024) // FIXME: size?
|
||||
{
|
||||
MidiDiskstream::Flag dflags = MidiDiskstream::Flag (0);
|
||||
|
||||
|
@ -74,6 +76,7 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo
|
|||
|
||||
MidiTrack::MidiTrack (Session& sess, const XMLNode& node)
|
||||
: Track (sess, node)
|
||||
, _immediate_events(1024) // FIXME: size?
|
||||
{
|
||||
_set_state(node, false);
|
||||
|
||||
|
@ -556,6 +559,8 @@ MidiTrack::process_output_buffers (BufferSet& bufs,
|
|||
if (muted()) {
|
||||
IO::silence(nframes, offset);
|
||||
} else {
|
||||
MidiBuffer& out_buf = bufs.get_midi(0);
|
||||
_immediate_events.read(out_buf, 0, 0, offset + nframes-1); // all stamps = 0
|
||||
deliver_output(bufs, start_frame, end_frame, nframes, offset);
|
||||
}
|
||||
}
|
||||
|
@ -620,3 +625,28 @@ MidiTrack::set_mode (TrackMode m)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \return true on success, false on failure (no buffer space left)
|
||||
*/
|
||||
bool
|
||||
MidiTrack::write_immediate_event(size_t size, const Byte* buf)
|
||||
{
|
||||
return (_immediate_events.write(0, size, buf) == size);
|
||||
}
|
||||
|
||||
void
|
||||
MidiTrack::MidiControl::set_value(float val)
|
||||
{
|
||||
assert(val >= 0);
|
||||
assert(val <= 127.0);
|
||||
|
||||
boost::shared_ptr<MidiTrack> midi_track = _route.lock();
|
||||
|
||||
if (midi_track && !_list->automation_playback()) {
|
||||
Byte ev[3] = { MIDI_CMD_CONTROL, _list->param_id().id(), (int)val };
|
||||
midi_track->write_immediate_event(3, ev);
|
||||
}
|
||||
|
||||
AutomationControl::set_value(val);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@ StreamPanner::StreamPanner (Panner& p, ParamID param)
|
|||
: parent (p)
|
||||
, _control (new PanControllable(p.session(), X_("panner"), *this, param))
|
||||
{
|
||||
assert(param.type() != NullAutomation);
|
||||
|
||||
_muted = false;
|
||||
|
||||
parent.session().add_controllable (_control);
|
||||
|
@ -189,8 +191,8 @@ StreamPanner::add_state (XMLNode& node)
|
|||
|
||||
/*---------------------------------------------------------------------- */
|
||||
|
||||
BaseStereoPanner::BaseStereoPanner (Panner& p)
|
||||
: StreamPanner (p, ParamID(PanAutomation, 0))
|
||||
BaseStereoPanner::BaseStereoPanner (Panner& p, ParamID param)
|
||||
: StreamPanner (p, param)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -346,8 +348,8 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain
|
|||
|
||||
/*---------------------------------------------------------------------- */
|
||||
|
||||
EqualPowerStereoPanner::EqualPowerStereoPanner (Panner& p)
|
||||
: BaseStereoPanner (p)
|
||||
EqualPowerStereoPanner::EqualPowerStereoPanner (Panner& p, ParamID param)
|
||||
: BaseStereoPanner (p, param)
|
||||
{
|
||||
update ();
|
||||
|
||||
|
@ -461,9 +463,9 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob
|
|||
}
|
||||
|
||||
StreamPanner*
|
||||
EqualPowerStereoPanner::factory (Panner& parent, ParamID who_cares)
|
||||
EqualPowerStereoPanner::factory (Panner& parent, ParamID param)
|
||||
{
|
||||
return new EqualPowerStereoPanner (parent);
|
||||
return new EqualPowerStereoPanner (parent, param);
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
|
@ -798,7 +800,7 @@ Panner::reset (uint32_t nouts, uint32_t npans)
|
|||
outputs.push_back (Output (1.0, 0));
|
||||
|
||||
for (n = 0; n < npans; ++n) {
|
||||
push_back (new EqualPowerStereoPanner (*this));
|
||||
push_back (new EqualPowerStereoPanner (*this, ParamID(PanAutomation, n)));
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in New Issue