/* 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;
}
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
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
/* 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);
}
parent_canvas,
_route->describe_parameter(param),
c->list()->param_id().to_string() /* FIXME: correct state name? */));
+
add_automation_child(param, track);
} else {
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;
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);
}
}
_show_automation.insert(param);
_route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
}
+
+ build_display_menu();
}
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);
};
/** 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;
#define __ardour_midi_track_h__
#include <ardour/track.h>
+#include <ardour/midi_ring_buffer.h>
namespace ARDOUR
{
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);
int set_diskstream (boost::shared_ptr<MidiDiskstream> ds);
void set_state_part_two ();
void set_state_part_three ();
+
+ MidiRingBuffer _immediate_events;
};
} /* namespace ARDOUR*/
#define __ardour_panner_h__
#include <cmath>
+#include <cassert>
#include <vector>
#include <string>
#include <iostream>
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;
class BaseStereoPanner : public StreamPanner
{
public:
- BaseStereoPanner (Panner&);
+ BaseStereoPanner (Panner&, ParamID param);
~BaseStereoPanner ();
/* this class just leaves the pan law itself to be defined
class EqualPowerStereoPanner : public BaseStereoPanner
{
public:
- EqualPowerStereoPanner (Panner&);
+ EqualPowerStereoPanner (Panner&, ParamID param);
~EqualPowerStereoPanner ();
void distribute_automated (AudioBuffer& src, BufferSet& obufs,
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") {
_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;
}
} else if (_type == MidiCCAutomation) {
return string_compose("midicc-%1", _id);
} else {
+ assert(false);
PBD::warning << "Uninitialized ParamID to_string() called." << endmsg;
return "";
}
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 {
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;
_lookup_cache.range.first = _events.end();
_sort_pending = false;
-
+ assert(_param_id.type() != NullAutomation);
AutomationListCreated(this);
}
}
mark_dirty ();
+ assert(_param_id.type() != NullAutomation);
AutomationListCreated(this);
}
mark_dirty ();
+ assert(_param_id.type() != NullAutomation);
AutomationListCreated(this);
}
if (id)
_param_id = id;
+ assert(_param_id.type() != NullAutomation);
AutomationListCreated(this);
}
#include <ardour/utils.h>
#include <ardour/buffer_set.h>
#include <ardour/meter.h>
+#include <ardour/midi_events.h>
#include "i18n.h"
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);
MidiTrack::MidiTrack (Session& sess, const XMLNode& node)
: Track (sess, node)
+ , _immediate_events(1024) // FIXME: size?
{
_set_state(node, false);
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);
}
}
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);
+}
+
: parent (p)
, _control (new PanControllable(p.session(), X_("panner"), *this, param))
{
+ assert(param.type() != NullAutomation);
+
_muted = false;
parent.session().add_controllable (_control);
/*---------------------------------------------------------------------- */
-BaseStereoPanner::BaseStereoPanner (Panner& p)
- : StreamPanner (p, ParamID(PanAutomation, 0))
+BaseStereoPanner::BaseStereoPanner (Panner& p, ParamID param)
+ : StreamPanner (p, param)
{
}
/*---------------------------------------------------------------------- */
-EqualPowerStereoPanner::EqualPowerStereoPanner (Panner& p)
- : BaseStereoPanner (p)
+EqualPowerStereoPanner::EqualPowerStereoPanner (Panner& p, ParamID param)
+ : BaseStereoPanner (p, param)
{
update ();
}
StreamPanner*
-EqualPowerStereoPanner::factory (Panner& parent, ParamID who_cares)
+EqualPowerStereoPanner::factory (Panner& parent, ParamID param)
{
- return new EqualPowerStereoPanner (parent);
+ return new EqualPowerStereoPanner (parent, param);
}
XMLNode&
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;