mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-10 08:36:32 +01:00
merge 12607:12717 from svn+ssh://ardoursvn@subversion.ardour.org/ardour2/branches/3.0
git-svn-id: svn://localhost/ardour2/branches/3.0-SG@12718 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
2b1fdfe815
commit
129dcd7f97
130 changed files with 2870 additions and 1065 deletions
|
|
@ -139,6 +139,7 @@
|
|||
<Option name="verbose canvas cursor" value="fffd2ebc"/>
|
||||
<Option name="vestigial frame" value="0000000f"/>
|
||||
<Option name="region base" value="99a7b5a0"/>
|
||||
<Option name="region area covered by another region" value="505050b0"/>
|
||||
<Option name="waveform outline" value="0f0f0fc8"/>
|
||||
<Option name="clipped waveform" value="ff0000e5"/>
|
||||
<Option name="waveform fill" value="3d4753dc"/>
|
||||
|
|
|
|||
|
|
@ -1050,16 +1050,21 @@ ARDOUR_UI::update_disk_space()
|
|||
return;
|
||||
}
|
||||
|
||||
framecnt_t frames = _session->available_capture_duration();
|
||||
boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
|
||||
char buf[64];
|
||||
framecnt_t fr = _session->frame_rate();
|
||||
|
||||
if (frames == max_framecnt) {
|
||||
if (!opt_frames) {
|
||||
/* Available space is unknown */
|
||||
snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
|
||||
} else if (opt_frames.get_value_or (0) == max_framecnt) {
|
||||
snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
|
||||
} else {
|
||||
rec_enabled_streams = 0;
|
||||
_session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
|
||||
|
||||
framecnt_t frames = opt_frames.get_value_or (0);
|
||||
|
||||
if (rec_enabled_streams) {
|
||||
frames /= rec_enabled_streams;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,6 +243,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
void maximise_editing_space ();
|
||||
void restore_editing_space ();
|
||||
|
||||
void update_tearoff_visibility ();
|
||||
|
||||
void setup_profile ();
|
||||
void setup_tooltips ();
|
||||
|
||||
|
|
@ -254,6 +256,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
void get_process_buffers ();
|
||||
void drop_process_buffers ();
|
||||
|
||||
void goto_editor_window ();
|
||||
|
||||
protected:
|
||||
friend class PublicEditor;
|
||||
|
||||
|
|
@ -279,7 +283,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
|
|||
ARDOUR::AudioEngine *engine;
|
||||
Gtk::Tooltips _tooltips;
|
||||
|
||||
void goto_editor_window ();
|
||||
void goto_mixer_window ();
|
||||
void toggle_mixer_window ();
|
||||
void toggle_mixer_on_top ();
|
||||
|
|
|
|||
|
|
@ -604,6 +604,14 @@ ARDOUR_UI::editor_realized ()
|
|||
reset_dpi ();
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::update_tearoff_visibility ()
|
||||
{
|
||||
if (editor) {
|
||||
editor->update_tearoff_visibility ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR_UI::maximise_editing_space ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -133,29 +133,25 @@ ARDOUR_UI::toggle_mixer_window ()
|
|||
void
|
||||
ARDOUR_UI::toggle_mixer_on_top ()
|
||||
{
|
||||
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer-on-top"));
|
||||
if (!act) {
|
||||
return;
|
||||
}
|
||||
/* Only called if the editor window received the shortcut key or if selected
|
||||
from the editor window menu, so the mixer is definitely not on top, and
|
||||
we can unconditionally make it so here.
|
||||
|
||||
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
|
||||
|
||||
if (tact->get_active()) {
|
||||
XXX this might not work so well where there is a global menu bar, e.g.
|
||||
on OS X.
|
||||
*/
|
||||
|
||||
/* Toggle the mixer to `visible' if required */
|
||||
act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
|
||||
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
|
||||
if (act) {
|
||||
tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
|
||||
Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
|
||||
|
||||
if (!tact->get_active()) {
|
||||
tact->set_active ();
|
||||
tact->set_active (true);
|
||||
}
|
||||
}
|
||||
|
||||
goto_mixer_window ();
|
||||
} else {
|
||||
goto_editor_window ();
|
||||
}
|
||||
}
|
||||
|
||||
/** The main editor window has been closed */
|
||||
|
|
|
|||
|
|
@ -225,11 +225,11 @@ ARDOUR_UI::install_actions ()
|
|||
/* windows visibility actions */
|
||||
|
||||
ActionManager::register_toggle_action (common_actions, X_("ToggleMaximalEditor"), _("Maximise Editor Space"), sigc::mem_fun (*this, &ARDOUR_UI::toggle_editing_space));
|
||||
act = ActionManager::register_toggle_action (common_actions, X_("KeepTearoffs"), _("Toolbars when Maximised"), mem_fun (*this, &ARDOUR_UI::toggle_keep_tearoffs));
|
||||
act = ActionManager::register_toggle_action (common_actions, X_("KeepTearoffs"), _("Show Toolbars"), mem_fun (*this, &ARDOUR_UI::toggle_keep_tearoffs));
|
||||
ActionManager::session_sensitive_actions.push_back (act);
|
||||
|
||||
ActionManager::register_toggle_action (common_actions, X_("toggle-mixer"), S_("Window|Mixer"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_mixer_window));
|
||||
ActionManager::register_toggle_action (common_actions, X_("toggle-mixer-on-top"), _("Mixer on Top"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_mixer_on_top));
|
||||
ActionManager::register_action (common_actions, X_("toggle-mixer-on-top"), _("Mixer on Top"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_mixer_on_top));
|
||||
ActionManager::register_toggle_action (common_actions, X_("ToggleRCOptionsEditor"), _("Preferences"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_rc_options_window));
|
||||
ActionManager::register_toggle_action (common_actions, X_("ToggleSessionOptionsEditor"), _("Properties"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_session_options_window));
|
||||
act = ActionManager::register_toggle_action (common_actions, X_("ToggleInspector"), _("Tracks and Busses"), sigc::mem_fun(*this, &ARDOUR_UI::toggle_route_params_window));
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ ARDOUR_UI::create_mixer ()
|
|||
|
||||
mixer->signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::main_window_state_event_handler), false));
|
||||
mixer->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-mixer")));
|
||||
mixer->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-mixer-on-top")));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ ARDOUR_UI::toggle_keep_tearoffs ()
|
|||
{
|
||||
ActionManager::toggle_config_state ("Common", "KeepTearoffs", &RCConfiguration::set_keep_tearoffs, &RCConfiguration::get_keep_tearoffs);
|
||||
|
||||
ARDOUR_UI::toggle_editing_space ();
|
||||
ARDOUR_UI::update_tearoff_visibility();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -137,23 +137,6 @@ AutomationController::end_touch ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutomationController::automation_state_changed ()
|
||||
{
|
||||
ENSURE_GUI_THREAD (*this, &AutomationController::automation_state_changed)
|
||||
|
||||
bool x = (_controllable->automation_state() != Off);
|
||||
|
||||
/* start watching automation so that things move */
|
||||
|
||||
_screen_update_connection.disconnect();
|
||||
|
||||
if (x) {
|
||||
_screen_update_connection = ARDOUR_UI::RapidScreenUpdate.connect (
|
||||
sigc::mem_fun (*this, &AutomationController::display_effective_value));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AutomationController::value_changed ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ private:
|
|||
void end_touch();
|
||||
|
||||
void value_changed();
|
||||
void automation_state_changed();
|
||||
|
||||
bool _ignore_change;
|
||||
boost::shared_ptr<ARDOUR::Automatable> _printer;
|
||||
|
|
|
|||
|
|
@ -136,7 +136,11 @@ void
|
|||
AutomationLine::show ()
|
||||
{
|
||||
if (_visible & Line) {
|
||||
if (alist->interpolation() != AutomationList::Discrete) {
|
||||
/* Only show the line there are some points, otherwise we may show an out-of-date line
|
||||
when automation points have been removed (the line will still follow the shape of the
|
||||
old points).
|
||||
*/
|
||||
if (alist->interpolation() != AutomationList::Discrete && control_points.size() >= 2) {
|
||||
line->show();
|
||||
} else {
|
||||
line->hide ();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
#include "canvas-flag.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "gtkmm2ext/utils.h"
|
||||
#include "gtkmm2ext/rgb_macros.h"
|
||||
|
||||
#include "ardour_ui.h"
|
||||
#include "canvas-flag.h"
|
||||
#include "time_axis_view_item.h"
|
||||
#include "utils.h"
|
||||
|
||||
using namespace Gnome::Canvas;
|
||||
using namespace std;
|
||||
|
|
@ -13,23 +19,23 @@ CanvasFlag::CanvasFlag (MidiRegionView& region,
|
|||
double x,
|
||||
double y)
|
||||
: Group(parent, x, y)
|
||||
, _text(0)
|
||||
, _name_pixbuf(0)
|
||||
, _height(height)
|
||||
, _outline_color_rgba(outline_color_rgba)
|
||||
, _fill_color_rgba(fill_color_rgba)
|
||||
, _region(region)
|
||||
, name_pixbuf_width (0)
|
||||
, _line(0)
|
||||
, _rect(0)
|
||||
{
|
||||
/* XXX this connection is needed if ::on_event() is changed to actually do anything */
|
||||
signal_event().connect (sigc::mem_fun (*this, &CanvasFlag::on_event));
|
||||
}
|
||||
|
||||
void
|
||||
CanvasFlag::delete_allocated_objects()
|
||||
{
|
||||
delete _text;
|
||||
_text = 0;
|
||||
delete _name_pixbuf;
|
||||
_name_pixbuf = 0;
|
||||
|
||||
delete _line;
|
||||
_line = 0;
|
||||
|
|
@ -39,28 +45,29 @@ CanvasFlag::delete_allocated_objects()
|
|||
}
|
||||
|
||||
void
|
||||
CanvasFlag::set_text(const string& a_text)
|
||||
CanvasFlag::set_text (const string& text)
|
||||
{
|
||||
delete_allocated_objects();
|
||||
|
||||
_text = new Text (*this, 0.0, 0.0, a_text);
|
||||
_text->property_justification() = Gtk::JUSTIFY_CENTER;
|
||||
_text->property_fill_color_rgba() = _outline_color_rgba;
|
||||
double flagwidth = _text->property_text_width() + 10.0;
|
||||
double flagheight = _text->property_text_height() + 3.0;
|
||||
_text->property_x() = flagwidth / 2.0;
|
||||
_text->property_y() = flagheight / 2.0;
|
||||
_text->show();
|
||||
_name_pixbuf = new ArdourCanvas::Pixbuf (*this);
|
||||
name_pixbuf_width = Gtkmm2ext::pixel_width (text, TimeAxisViewItem::NAME_FONT) + 2;
|
||||
Gdk::Color c;
|
||||
set_color (c, _outline_color_rgba);
|
||||
_name_pixbuf->property_pixbuf() = Gtkmm2ext::pixbuf_from_string (text, TimeAxisViewItem::NAME_FONT, name_pixbuf_width,
|
||||
TimeAxisViewItem::NAME_HEIGHT, c);
|
||||
_name_pixbuf->property_x() = 10.0;
|
||||
_name_pixbuf->property_y() = 2.0;
|
||||
_name_pixbuf->show();
|
||||
|
||||
double flagwidth = name_pixbuf_width + 8.0;
|
||||
double flagheight = TimeAxisViewItem::NAME_HEIGHT + 3.0;
|
||||
_line = new SimpleLine(*this, 0.0, 0.0, 0.0, _height);
|
||||
_line->property_color_rgba() = _outline_color_rgba;
|
||||
_rect = new SimpleRect(*this, 0.0, 0.0, flagwidth, flagheight);
|
||||
_rect->property_outline_color_rgba() = _outline_color_rgba;
|
||||
_rect->property_fill_color_rgba() = _fill_color_rgba;
|
||||
_text->raise_to_top();
|
||||
|
||||
/* XXX these two connections are needed if ::on_event() is changed to actually do anything */
|
||||
//_rect->signal_event().connect (sigc::mem_fun (*this, &CanvasFlag::on_event));
|
||||
//_text->signal_event().connect (sigc::mem_fun (*this, &CanvasFlag::on_event));
|
||||
_name_pixbuf->raise_to_top();
|
||||
}
|
||||
|
||||
CanvasFlag::~CanvasFlag()
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
#define CANVASFLAG_H_
|
||||
|
||||
#include <string>
|
||||
#include <libgnomecanvasmm/pixbuf.h>
|
||||
#include <libgnomecanvasmm/group.h>
|
||||
#include <libgnomecanvasmm/widget.h>
|
||||
#include <libgnomecanvasmm/text.h>
|
||||
|
||||
#include "simplerect.h"
|
||||
#include "simpleline.h"
|
||||
#include "canvas.h"
|
||||
|
||||
class MidiRegionView;
|
||||
|
||||
|
|
@ -17,7 +18,7 @@ namespace Canvas {
|
|||
class CanvasFlag : public Group
|
||||
{
|
||||
public:
|
||||
CanvasFlag(MidiRegionView& region,
|
||||
CanvasFlag (MidiRegionView& region,
|
||||
Group& parent,
|
||||
double height,
|
||||
guint outline_color_rgba = 0xc0c0c0ff,
|
||||
|
|
@ -32,12 +33,15 @@ public:
|
|||
virtual void set_text(const std::string& a_text);
|
||||
virtual void set_height (double);
|
||||
|
||||
int width () const { return name_pixbuf_width + 10.0; }
|
||||
|
||||
protected:
|
||||
Text* _text;
|
||||
ArdourCanvas::Pixbuf* _name_pixbuf;
|
||||
double _height;
|
||||
guint _outline_color_rgba;
|
||||
guint _fill_color_rgba;
|
||||
MidiRegionView& _region;
|
||||
int name_pixbuf_width;
|
||||
|
||||
private:
|
||||
void delete_allocated_objects();
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include <glibmm/regex.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "gtkmm2ext/keyboard.h"
|
||||
#include "ardour/midi_patch_manager.h"
|
||||
#include "ardour/instrument_info.h"
|
||||
|
||||
#include "ardour_ui.h"
|
||||
#include "midi_region_view.h"
|
||||
|
|
@ -44,8 +44,7 @@ CanvasPatchChange::CanvasPatchChange(
|
|||
double height,
|
||||
double x,
|
||||
double y,
|
||||
string& model_name,
|
||||
string& custom_device_mode,
|
||||
ARDOUR::InstrumentInfo& info,
|
||||
ARDOUR::MidiModel::PatchChangePtr patch,
|
||||
bool active_channel)
|
||||
: CanvasFlag(
|
||||
|
|
@ -60,12 +59,11 @@ CanvasPatchChange::CanvasPatchChange(
|
|||
ARDOUR_UI::config()->canvasvar_MidiPatchChangeInactiveChannelFill.get(),
|
||||
x,
|
||||
y)
|
||||
, _model_name(model_name)
|
||||
, _custom_device_mode(custom_device_mode)
|
||||
, _info (info)
|
||||
, _patch (patch)
|
||||
, _popup_initialized(false)
|
||||
{
|
||||
set_text(text);
|
||||
set_text (text);
|
||||
}
|
||||
|
||||
CanvasPatchChange::~CanvasPatchChange()
|
||||
|
|
@ -75,9 +73,7 @@ CanvasPatchChange::~CanvasPatchChange()
|
|||
void
|
||||
CanvasPatchChange::initialize_popup_menus()
|
||||
{
|
||||
boost::shared_ptr<ChannelNameSet> channel_name_set =
|
||||
MidiPatchManager::instance()
|
||||
.find_channel_name_set(_model_name, _custom_device_mode, _patch->channel());
|
||||
boost::shared_ptr<ChannelNameSet> channel_name_set = _info.get_patches (_patch->channel());
|
||||
|
||||
if (!channel_name_set) {
|
||||
return;
|
||||
|
|
@ -91,9 +87,6 @@ CanvasPatchChange::initialize_popup_menus()
|
|||
for (ChannelNameSet::PatchBanks::const_iterator bank = patch_banks.begin();
|
||||
bank != patch_banks.end();
|
||||
++bank) {
|
||||
Glib::RefPtr<Glib::Regex> underscores = Glib::Regex::create("_");
|
||||
std::string replacement(" ");
|
||||
|
||||
Gtk::Menu& patch_bank_menu = *manage(new Gtk::Menu());
|
||||
|
||||
const PatchBank::PatchNameList& patches = (*bank)->patch_name_list();
|
||||
|
|
@ -102,7 +95,8 @@ CanvasPatchChange::initialize_popup_menus()
|
|||
for (PatchBank::PatchNameList::const_iterator patch = patches.begin();
|
||||
patch != patches.end();
|
||||
++patch) {
|
||||
std::string name = underscores->replace((*patch)->name().c_str(), -1, 0, replacement);
|
||||
std::string name = (*patch)->name();
|
||||
boost::replace_all (name, "_", " ");
|
||||
|
||||
patch_menus.push_back(
|
||||
Gtk::Menu_Helpers::MenuElem(
|
||||
|
|
@ -112,8 +106,8 @@ CanvasPatchChange::initialize_popup_menus()
|
|||
(*patch)->patch_primary_key())) );
|
||||
}
|
||||
|
||||
|
||||
std::string name = underscores->replace((*bank)->name().c_str(), -1, 0, replacement);
|
||||
std::string name = (*bank)->name();
|
||||
boost::replace_all (name, "_", " ");
|
||||
|
||||
patch_bank_menus.push_back(
|
||||
Gtk::Menu_Helpers::MenuElem(
|
||||
|
|
@ -193,6 +187,10 @@ CanvasPatchChange::on_event (GdkEvent* ev)
|
|||
break;
|
||||
|
||||
case GDK_SCROLL:
|
||||
{
|
||||
/* XXX: icky dcast */
|
||||
Editor* e = dynamic_cast<Editor*> (&_region.get_time_axis_view().editor());
|
||||
if (e->current_mouse_mode() == Editing::MouseObject && e->internal_editing()) {
|
||||
if (ev->scroll.direction == GDK_SCROLL_UP) {
|
||||
if (Keyboard::modifier_state_contains (ev->scroll.state, Keyboard::PrimaryModifier)) {
|
||||
_region.previous_bank (*this);
|
||||
|
|
@ -209,6 +207,8 @@ CanvasPatchChange::on_event (GdkEvent* ev)
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
_region.patch_entered (this);
|
||||
|
|
@ -218,9 +218,6 @@ CanvasPatchChange::on_event (GdkEvent* ev)
|
|||
_region.patch_left (this);
|
||||
break;
|
||||
|
||||
case GDK_BUTTON_RELEASE:
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ namespace MIDI {
|
|||
}
|
||||
}
|
||||
|
||||
namespace ARDOUR {
|
||||
class InstrumentInfo;
|
||||
}
|
||||
|
||||
namespace Gnome {
|
||||
namespace Canvas {
|
||||
|
||||
|
|
@ -43,8 +47,7 @@ public:
|
|||
double height,
|
||||
double x,
|
||||
double y,
|
||||
string& model_name,
|
||||
string& custom_device_mode,
|
||||
ARDOUR::InstrumentInfo& info,
|
||||
ARDOUR::MidiModel::PatchChangePtr patch,
|
||||
bool
|
||||
);
|
||||
|
|
@ -53,8 +56,6 @@ public:
|
|||
|
||||
virtual bool on_event(GdkEvent* ev);
|
||||
|
||||
string model_name () const { return _model_name; }
|
||||
string custom_device_mode () const { return _custom_device_mode; }
|
||||
ARDOUR::MidiModel::PatchChangePtr patch () const { return _patch; }
|
||||
|
||||
void initialize_popup_menus();
|
||||
|
|
@ -62,8 +63,7 @@ public:
|
|||
void on_patch_menu_selected(const MIDI::Name::PatchPrimaryKey& key);
|
||||
|
||||
private:
|
||||
string _model_name;
|
||||
string _custom_device_mode;
|
||||
ARDOUR::InstrumentInfo& _info;
|
||||
ARDOUR::MidiModel::PatchChangePtr _patch;
|
||||
Gtk::Menu _popup;
|
||||
bool _popup_initialized;
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ CANVAS_VARIABLE(canvasvar_TrimHandle, "trim handle")
|
|||
CANVAS_VARIABLE(canvasvar_VerboseCanvasCursor, "verbose canvas cursor")
|
||||
CANVAS_VARIABLE(canvasvar_VestigialFrame, "vestigial frame")
|
||||
CANVAS_VARIABLE(canvasvar_FrameBase, "region base")
|
||||
CANVAS_VARIABLE(canvasvar_CoveredRegion, "region area covered by another region")
|
||||
CANVAS_VARIABLE(canvasvar_WaveForm, "waveform outline")
|
||||
CANVAS_VARIABLE(canvasvar_WaveFormClip, "clipped waveform")
|
||||
CANVAS_VARIABLE(canvasvar_WaveFormFill, "waveform fill")
|
||||
|
|
|
|||
|
|
@ -28,21 +28,27 @@
|
|||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Gtk;
|
||||
using namespace Gtkmm2ext;
|
||||
|
||||
/**
|
||||
* EditNoteDialog constructor.
|
||||
*
|
||||
* @param n Note to edit.
|
||||
* @param n Notes to edit.
|
||||
*/
|
||||
|
||||
EditNoteDialog::EditNoteDialog (MidiRegionView* rv, Gnome::Canvas::CanvasNoteEvent* ev)
|
||||
EditNoteDialog::EditNoteDialog (MidiRegionView* rv, set<ArdourCanvas::CanvasNoteEvent*> n)
|
||||
: ArdourDialog (_("Note"))
|
||||
, _region_view (rv)
|
||||
, _event (ev)
|
||||
, _events (n)
|
||||
, _channel_all (_("Set selected notes to this channel"))
|
||||
, _pitch_all (_("Set selected notes to this pitch"))
|
||||
, _velocity_all (_("Set selected notes to this velocity"))
|
||||
, _time_clock (X_("notetime"), true, "", true, false)
|
||||
, _time_all (_("Set selected notes to this time"))
|
||||
, _length_clock (X_("notelength"), true, "", true, false, true)
|
||||
, _length_all (_("Set selected notes to this length"))
|
||||
{
|
||||
Table* table = manage (new Table (4, 2));
|
||||
table->set_spacings (6);
|
||||
|
|
@ -52,47 +58,88 @@ EditNoteDialog::EditNoteDialog (MidiRegionView* rv, Gnome::Canvas::CanvasNoteEve
|
|||
Label* l = manage (left_aligned_label (_("Channel")));
|
||||
table->attach (*l, 0, 1, r, r + 1);
|
||||
table->attach (_channel, 1, 2, r, r + 1);
|
||||
table->attach (_channel_all, 2, 3, r, r + 1);
|
||||
++r;
|
||||
|
||||
_channel.set_range (1, 16);
|
||||
_channel.set_increments (1, 2);
|
||||
_channel.set_value (ev->note()->channel () + 1);
|
||||
_channel.set_value ((*_events.begin())->note()->channel () + 1);
|
||||
|
||||
l = manage (left_aligned_label (_("Pitch")));
|
||||
table->attach (*l, 0, 1, r, r + 1);
|
||||
table->attach (_pitch, 1, 2, r, r + 1);
|
||||
table->attach (_pitch_all, 2, 3, r, r + 1);
|
||||
++r;
|
||||
|
||||
_pitch.set_range (0, 127);
|
||||
_pitch.set_increments (1, 10);
|
||||
_pitch.set_value (ev->note()->note ());
|
||||
_pitch.set_value ((*_events.begin())->note()->note());
|
||||
|
||||
l = manage (left_aligned_label (_("Velocity")));
|
||||
table->attach (*l, 0, 1, r, r + 1);
|
||||
table->attach (_velocity, 1, 2, r, r + 1);
|
||||
table->attach (_velocity_all, 2, 3, r, r + 1);
|
||||
++r;
|
||||
|
||||
_velocity.set_range (0, 127);
|
||||
_velocity.set_increments (1, 10);
|
||||
_velocity.set_value (ev->note()->velocity ());
|
||||
_velocity.set_value ((*_events.begin())->note()->velocity ());
|
||||
|
||||
l = manage (left_aligned_label (_("Time")));
|
||||
table->attach (*l, 0, 1, r, r + 1);
|
||||
table->attach (_time_clock, 1, 2, r, r + 1);
|
||||
table->attach (_time_all, 2, 3, r, r + 1);
|
||||
++r;
|
||||
|
||||
_time_clock.set_session (_region_view->get_time_axis_view().session ());
|
||||
_time_clock.set_mode (AudioClock::BBT);
|
||||
_time_clock.set (_region_view->source_relative_time_converter().to (ev->note()->time ()), true);
|
||||
_time_clock.set (_region_view->source_relative_time_converter().to ((*_events.begin())->note()->time ()), true);
|
||||
|
||||
l = manage (left_aligned_label (_("Length")));
|
||||
table->attach (*l, 0, 1, r, r + 1);
|
||||
table->attach (_length_clock, 1, 2, r, r + 1);
|
||||
table->attach (_length_all, 2, 3, r, r + 1);
|
||||
++r;
|
||||
|
||||
_length_clock.set_session (_region_view->get_time_axis_view().session ());
|
||||
_length_clock.set_mode (AudioClock::BBT);
|
||||
_length_clock.set (_region_view->region_relative_time_converter().to (ev->note()->length ()), true);
|
||||
_length_clock.set (_region_view->region_relative_time_converter().to ((*_events.begin())->note()->length ()), true);
|
||||
|
||||
/* Set up `set all notes...' buttons' sensitivity */
|
||||
|
||||
_channel_all.set_sensitive (false);
|
||||
_pitch_all.set_sensitive (false);
|
||||
_velocity_all.set_sensitive (false);
|
||||
_time_all.set_sensitive (false);
|
||||
_length_all.set_sensitive (false);
|
||||
|
||||
int test_channel = (*_events.begin())->note()->channel ();
|
||||
int test_pitch = (*_events.begin())->note()->note ();
|
||||
int test_velocity = (*_events.begin())->note()->velocity ();
|
||||
double test_time = (*_events.begin())->note()->time ();
|
||||
double test_length = (*_events.begin())->note()->length ();
|
||||
|
||||
for (set<ArdourCanvas::CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||
if ((*i)->note()->channel() != test_channel) {
|
||||
_channel_all.set_sensitive (true);
|
||||
}
|
||||
|
||||
if ((*i)->note()->note() != test_pitch) {
|
||||
_pitch_all.set_sensitive (true);
|
||||
}
|
||||
|
||||
if ((*i)->note()->velocity() != test_velocity) {
|
||||
_velocity_all.set_sensitive (true);
|
||||
}
|
||||
|
||||
if ((*i)->note()->time () != test_time) {
|
||||
_time_all.set_sensitive (true);
|
||||
}
|
||||
|
||||
if ((*i)->note()->length () != test_length) {
|
||||
_length_all.set_sensitive (true);
|
||||
}
|
||||
}
|
||||
|
||||
get_vbox()->pack_start (*table);
|
||||
|
||||
|
|
@ -122,34 +169,54 @@ EditNoteDialog::run ()
|
|||
|
||||
bool had_change = false;
|
||||
|
||||
if (_channel.get_value_as_int() - 1 != _event->note()->channel()) {
|
||||
_region_view->change_note_channel (_event, _channel.get_value_as_int () - 1);
|
||||
if (!_channel_all.get_sensitive() || _channel_all.get_active ()) {
|
||||
for (set<ArdourCanvas::CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||
if (_channel.get_value_as_int() - 1 != (*i)->note()->channel()) {
|
||||
_region_view->change_note_channel (*i, _channel.get_value_as_int () - 1);
|
||||
had_change = true;
|
||||
}
|
||||
|
||||
if (_pitch.get_value_as_int() != _event->note()->note()) {
|
||||
_region_view->change_note_note (_event, _pitch.get_value_as_int (), false);
|
||||
had_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_velocity.get_value_as_int() != _event->note()->velocity()) {
|
||||
_region_view->change_note_velocity (_event, _velocity.get_value_as_int (), false);
|
||||
if (!_pitch_all.get_sensitive() || _pitch_all.get_active ()) {
|
||||
for (set<ArdourCanvas::CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||
if (_pitch.get_value_as_int() != (*i)->note()->note()) {
|
||||
_region_view->change_note_note (*i, _pitch.get_value_as_int ());
|
||||
had_change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_velocity_all.get_sensitive() || _velocity_all.get_active ()) {
|
||||
for (set<ArdourCanvas::CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||
if (_velocity.get_value_as_int() != (*i)->note()->velocity()) {
|
||||
_region_view->change_note_velocity (*i, _velocity.get_value_as_int ());
|
||||
had_change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double const t = _region_view->source_relative_time_converter().from (_time_clock.current_time ());
|
||||
|
||||
if (t != _event->note()->time()) {
|
||||
_region_view->change_note_time (_event, t);
|
||||
if (!_time_all.get_sensitive() || _time_all.get_active ()) {
|
||||
for (set<ArdourCanvas::CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||
if (t != (*i)->note()->time()) {
|
||||
_region_view->change_note_time (*i, t);
|
||||
had_change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double const d = _region_view->region_relative_time_converter().from (_length_clock.current_duration ());
|
||||
|
||||
if (d != _event->note()->length()) {
|
||||
_region_view->change_note_length (_event, d);
|
||||
if (!_length_all.get_sensitive() || _length_all.get_active ()) {
|
||||
for (set<ArdourCanvas::CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||
if (d != (*i)->note()->length()) {
|
||||
_region_view->change_note_length (*i, d);
|
||||
had_change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!had_change) {
|
||||
_region_view->abort_command ();
|
||||
|
|
@ -157,7 +224,9 @@ EditNoteDialog::run ()
|
|||
|
||||
_region_view->apply_diff ();
|
||||
|
||||
_event->set_selected (_event->selected()); // change color
|
||||
for (set<ArdourCanvas::CanvasNoteEvent*>::iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||
(*i)->set_selected ((*i)->selected()); // change color
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,16 +33,21 @@ namespace Gnome {
|
|||
class EditNoteDialog : public ArdourDialog
|
||||
{
|
||||
public:
|
||||
EditNoteDialog (MidiRegionView *, Gnome::Canvas::CanvasNoteEvent *);
|
||||
EditNoteDialog (MidiRegionView *, std::set<Gnome::Canvas::CanvasNoteEvent*>);
|
||||
|
||||
int run ();
|
||||
|
||||
private:
|
||||
MidiRegionView* _region_view;
|
||||
Gnome::Canvas::CanvasNoteEvent* _event;
|
||||
std::set<Gnome::Canvas::CanvasNoteEvent*> _events;
|
||||
Gtk::SpinButton _channel;
|
||||
Gtk::CheckButton _channel_all;
|
||||
Gtk::SpinButton _pitch;
|
||||
Gtk::CheckButton _pitch_all;
|
||||
Gtk::SpinButton _velocity;
|
||||
Gtk::CheckButton _velocity_all;
|
||||
AudioClock _time_clock;
|
||||
Gtk::CheckButton _time_all;
|
||||
AudioClock _length_clock;
|
||||
Gtk::CheckButton _length_all;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3928,6 +3928,15 @@ Editor::session_state_saved (string)
|
|||
_snapshots->redisplay ();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::update_tearoff_visibility()
|
||||
{
|
||||
bool visible = Config->get_keep_tearoffs();
|
||||
_mouse_mode_tearoff->set_visible (visible);
|
||||
_tools_tearoff->set_visible (visible);
|
||||
_zoom_tearoff->set_visible (visible);
|
||||
}
|
||||
|
||||
void
|
||||
Editor::maximise_editing_space ()
|
||||
{
|
||||
|
|
@ -3937,15 +3946,6 @@ Editor::maximise_editing_space ()
|
|||
|
||||
fullscreen ();
|
||||
|
||||
if (!Config->get_keep_tearoffs()) {
|
||||
/* these calls will leave each tearoff visible *if* it is torn off,
|
||||
but invisible otherwise.
|
||||
*/
|
||||
_mouse_mode_tearoff->set_visible (false);
|
||||
_tools_tearoff->set_visible (false);
|
||||
_zoom_tearoff->set_visible (false);
|
||||
}
|
||||
|
||||
_maximised = true;
|
||||
}
|
||||
|
||||
|
|
@ -3958,12 +3958,6 @@ Editor::restore_editing_space ()
|
|||
|
||||
unfullscreen();
|
||||
|
||||
if (!Config->get_keep_tearoffs()) {
|
||||
_mouse_mode_tearoff->set_visible (true);
|
||||
_tools_tearoff->set_visible (true);
|
||||
_zoom_tearoff->set_visible (true);
|
||||
}
|
||||
|
||||
_maximised = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,9 +63,12 @@
|
|||
#include "canvas.h"
|
||||
#include "window_proxy.h"
|
||||
|
||||
namespace Gnome { namespace Canvas {
|
||||
namespace Gnome {
|
||||
namespace Canvas {
|
||||
class NoEventText;
|
||||
} }
|
||||
class CanvasNoteEvent;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gtkmm2ext {
|
||||
class TearOff;
|
||||
|
|
@ -397,6 +400,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
void maximise_editing_space();
|
||||
void restore_editing_space();
|
||||
|
||||
void update_tearoff_visibility();
|
||||
|
||||
void reset_x_origin (framepos_t);
|
||||
void reset_x_origin_to_follow_playhead ();
|
||||
void reset_y_origin (double);
|
||||
|
|
@ -1489,7 +1494,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
|
|||
void edit_tempo_marker (ArdourCanvas::Item*);
|
||||
void edit_meter_marker (ArdourCanvas::Item*);
|
||||
void edit_control_point (ArdourCanvas::Item*);
|
||||
void edit_note (ArdourCanvas::Item *);
|
||||
void edit_notes (std::set<Gnome::Canvas::CanvasNoteEvent *> const &);
|
||||
|
||||
void marker_menu_edit ();
|
||||
void marker_menu_remove ();
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ Editor::session_import_dialog ()
|
|||
typedef std::map<PBD::ID,boost::shared_ptr<ARDOUR::Source> > SourceMap;
|
||||
|
||||
/**
|
||||
* Updating is still disabled, see note in libs/ardour/import.cc Session::import_audiofiles()
|
||||
* Updating is still disabled, see note in libs/ardour/import.cc Session::import_files()
|
||||
*
|
||||
* all_or_nothing:
|
||||
* true = show "Update", "Import" and "Skip"
|
||||
|
|
@ -546,7 +546,7 @@ Editor::import_sndfiles (vector<string> paths, ImportMode mode, SrcQuality quali
|
|||
set_canvas_cursor (_cursors->wait);
|
||||
gdk_flush ();
|
||||
|
||||
/* start import thread for this spec. this will ultimately call Session::import_audiofiles()
|
||||
/* start import thread for this spec. this will ultimately call Session::import_files()
|
||||
which, if successful, will add the files as regions to the region list. its up to us
|
||||
(the GUI) to direct additional steps after that.
|
||||
*/
|
||||
|
|
@ -788,7 +788,7 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
|
|||
*/
|
||||
framecnt_t len = (*x)->length (pos);
|
||||
if (len == 0) {
|
||||
len = (60 / 120) * _session->frame_rate ();
|
||||
len = (60.0 / 120.0) * _session->frame_rate ();
|
||||
}
|
||||
|
||||
plist.add (ARDOUR::Properties::start, 0);
|
||||
|
|
@ -827,6 +827,8 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
|
|||
int n = 0;
|
||||
framepos_t rlen = 0;
|
||||
|
||||
begin_reversible_command (Operations::insert_file);
|
||||
|
||||
for (vector<boost::shared_ptr<Region> >::iterator r = regions.begin(); r != regions.end(); ++r, ++n) {
|
||||
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (*r);
|
||||
|
||||
|
|
@ -874,6 +876,8 @@ Editor::add_sources (vector<string> paths, SourceList& sources, framepos_t& pos,
|
|||
}
|
||||
}
|
||||
|
||||
commit_reversible_command ();
|
||||
|
||||
/* setup peak file building in another thread */
|
||||
|
||||
for (SourceList::iterator x = sources.begin(); x != sources.end(); ++x) {
|
||||
|
|
@ -912,11 +916,9 @@ Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t
|
|||
|
||||
boost::shared_ptr<Playlist> playlist = existing_track->playlist();
|
||||
boost::shared_ptr<Region> copy (RegionFactory::create (region, region->properties()));
|
||||
begin_reversible_command (Operations::insert_file);
|
||||
playlist->clear_changes ();
|
||||
playlist->add_region (copy, pos);
|
||||
_session->add_command (new StatefulDiffCommand (playlist));
|
||||
commit_reversible_command ();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -945,12 +947,10 @@ Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t
|
|||
}
|
||||
|
||||
boost::shared_ptr<Playlist> playlist = existing_track->playlist();
|
||||
boost::shared_ptr<Region> copy (RegionFactory::create (region));
|
||||
begin_reversible_command (Operations::insert_file);
|
||||
boost::shared_ptr<Region> copy (RegionFactory::create (region, true));
|
||||
playlist->clear_changes ();
|
||||
playlist->add_region (copy, pos);
|
||||
_session->add_command (new StatefulDiffCommand (playlist));
|
||||
commit_reversible_command ();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -963,12 +963,10 @@ Editor::finish_bringing_in_material (boost::shared_ptr<Region> region, uint32_t
|
|||
list<boost::shared_ptr<AudioTrack> > at (_session->new_audio_track (in_chans, out_chans, Destructive));
|
||||
if (!at.empty()) {
|
||||
boost::shared_ptr<Playlist> playlist = at.front()->playlist();
|
||||
boost::shared_ptr<Region> copy (RegionFactory::create (region));
|
||||
begin_reversible_command (Operations::insert_file);
|
||||
boost::shared_ptr<Region> copy (RegionFactory::create (region, true));
|
||||
playlist->clear_changes ();
|
||||
playlist->add_region (copy, pos);
|
||||
_session->add_command (new StatefulDiffCommand (playlist));
|
||||
commit_reversible_command ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -989,7 +987,7 @@ Editor::_import_thread (void *arg)
|
|||
void *
|
||||
Editor::import_thread ()
|
||||
{
|
||||
_session->import_audiofiles (import_status);
|
||||
_session->import_files (import_status);
|
||||
pthread_exit_pbd (0);
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1013,7 +1013,7 @@ Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const & /*c*/,
|
|||
return true;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Region> region_copy = RegionFactory::create (region);
|
||||
boost::shared_ptr<Region> region_copy = RegionFactory::create (region, true);
|
||||
|
||||
if (boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 &&
|
||||
dynamic_cast<AudioTimeAxisView*> (tv.first) == 0) {
|
||||
|
|
|
|||
|
|
@ -1495,10 +1495,6 @@ RegionCreateDrag::finished (GdkEvent*, bool movement_occurred)
|
|||
} else {
|
||||
_view->playlist()->thaw ();
|
||||
}
|
||||
|
||||
if (_region) {
|
||||
_editor->commit_reversible_command ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4003,7 +3999,15 @@ NoteDrag::total_dx () const
|
|||
int8_t
|
||||
NoteDrag::total_dy () const
|
||||
{
|
||||
return ((int8_t) (grab_y() / _note_height)) - ((int8_t) (_drags->current_pointer_y() / _note_height));
|
||||
MidiStreamView* msv = _region->midi_stream_view ();
|
||||
double const y = _region->midi_view()->y_position ();
|
||||
/* new current note */
|
||||
uint8_t n = msv->y_to_note (_drags->current_pointer_y () - y);
|
||||
/* clamp */
|
||||
n = max (msv->lowest_note(), n);
|
||||
n = min (msv->highest_note(), n);
|
||||
/* and work out delta */
|
||||
return n - msv->y_to_note (grab_y() - y);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4313,7 +4317,9 @@ PatchChangeDrag::PatchChangeDrag (Editor* e, CanvasPatchChange* i, MidiRegionVie
|
|||
, _patch_change (i)
|
||||
, _cumulative_dx (0)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::Drags, "New PatchChangeDrag\n");
|
||||
DEBUG_TRACE (DEBUG::Drags, string_compose ("New PatchChangeDrag, patch @ %1, grab @ %2\n",
|
||||
_region_view->source_beats_to_absolute_frames (_patch_change->patch()->time()),
|
||||
grab_frame()));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4324,8 +4330,8 @@ PatchChangeDrag::motion (GdkEvent* ev, bool)
|
|||
f = max (f, r->position ());
|
||||
f = min (f, r->last_frame ());
|
||||
|
||||
framecnt_t const dxf = f - grab_frame();
|
||||
double const dxu = _editor->frame_to_unit (dxf);
|
||||
framecnt_t const dxf = f - grab_frame(); // permitted dx in frames
|
||||
double const dxu = _editor->frame_to_unit (dxf); // permitted fx in units
|
||||
_patch_change->move (dxu - _cumulative_dx, 0);
|
||||
_cumulative_dx = dxu;
|
||||
}
|
||||
|
|
@ -4338,14 +4344,13 @@ PatchChangeDrag::finished (GdkEvent* ev, bool movement_occurred)
|
|||
}
|
||||
|
||||
boost::shared_ptr<Region> r (_region_view->region ());
|
||||
|
||||
framepos_t f = adjusted_current_frame (ev);
|
||||
f = max (f, r->position ());
|
||||
f = min (f, r->last_frame ());
|
||||
|
||||
_region_view->move_patch_change (
|
||||
*_patch_change,
|
||||
_region_view->region_frames_to_region_beats (f - r->position() - r->start())
|
||||
_region_view->region_frames_to_region_beats (f - (r->position() - r->start()))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -4561,8 +4566,6 @@ NoteCreateDrag::aborted (bool)
|
|||
|
||||
}
|
||||
|
||||
/*------------*/
|
||||
|
||||
CrossfadeEdgeDrag::CrossfadeEdgeDrag (Editor* e, AudioRegionView* rv, ArdourCanvas::Item* i, bool start_yn)
|
||||
: Drag (e, i)
|
||||
, arv (rv)
|
||||
|
|
@ -4644,6 +4647,7 @@ CrossfadeEdgeDrag::finished (GdkEvent*, bool)
|
|||
vector<Command*> cmds;
|
||||
ar->playlist()->rdiff (cmds);
|
||||
_editor->session()->add_commands (cmds);
|
||||
_editor->commit_reversible_command ();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1003,8 +1003,23 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (clicked_axisview);
|
||||
assert (atv);
|
||||
if (parent && dynamic_cast<MidiTimeAxisView*> (parent) && atv->show_regions ()) {
|
||||
/* create a MIDI region so that we have somewhere to put automation */
|
||||
|
||||
RouteTimeAxisView* p = dynamic_cast<RouteTimeAxisView*> (parent);
|
||||
assert (p);
|
||||
boost::shared_ptr<Playlist> pl = p->track()->playlist ();
|
||||
if (pl->n_regions() == 0) {
|
||||
/* Parent has no regions; create one so that we have somewhere to put automation */
|
||||
_drags->set (new RegionCreateDrag (this, item, parent), event);
|
||||
} else {
|
||||
/* See if there's a region before the click that we can extend, and extend it if so */
|
||||
framepos_t const t = event_frame (event);
|
||||
boost::shared_ptr<Region> prev = pl->find_next_region (t, End, -1);
|
||||
if (!prev) {
|
||||
_drags->set (new RegionCreateDrag (this, item, parent), event);
|
||||
} else {
|
||||
prev->set_length (t - prev->position ());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* rubberband drag to select automation points */
|
||||
_drags->set (new EditorRubberbandSelectDrag (this, item), event);
|
||||
|
|
@ -1423,8 +1438,12 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
|
|||
break;
|
||||
|
||||
case NoteItem:
|
||||
edit_note (item);
|
||||
{
|
||||
ArdourCanvas::CanvasNoteEvent* e = dynamic_cast<ArdourCanvas::CanvasNoteEvent*> (item);
|
||||
assert (e);
|
||||
edit_notes (e->region_view().selection ());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
@ -2292,12 +2311,13 @@ Editor::edit_control_point (ArdourCanvas::Item* item)
|
|||
}
|
||||
|
||||
void
|
||||
Editor::edit_note (ArdourCanvas::Item* item)
|
||||
Editor::edit_notes (MidiRegionView::Selection const & s)
|
||||
{
|
||||
ArdourCanvas::CanvasNoteEvent* e = dynamic_cast<ArdourCanvas::CanvasNoteEvent*> (item);
|
||||
assert (e);
|
||||
if (s.empty ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EditNoteDialog d (&e->region_view(), e);
|
||||
EditNoteDialog d (&(*s.begin())->region_view(), s);
|
||||
d.set_position (Gtk::WIN_POS_MOUSE);
|
||||
ensure_float (d);
|
||||
|
||||
|
|
|
|||
|
|
@ -4730,6 +4730,8 @@ Editor::insert_patch_change (bool from_context)
|
|||
|
||||
const framepos_t p = get_preferred_edit_position (false, from_context);
|
||||
|
||||
cerr << "Got " << rs.size() << " regions to add patch change to\n";
|
||||
|
||||
/* XXX: bit of a hack; use the MIDNAM from the first selected region;
|
||||
there may be more than one, but the PatchChangeDialog can only offer
|
||||
one set of patch menus.
|
||||
|
|
@ -4737,7 +4739,7 @@ Editor::insert_patch_change (bool from_context)
|
|||
MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
|
||||
|
||||
Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
|
||||
PatchChangeDialog d (0, _session, empty, first->model_name(), first->custom_device_mode(), Gtk::Stock::ADD);
|
||||
PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
|
||||
|
||||
if (d.run() == RESPONSE_CANCEL) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -310,6 +310,8 @@ EditorSummary::centre_on_click (GdkEventButton* ev)
|
|||
bool
|
||||
EditorSummary::on_button_press_event (GdkEventButton* ev)
|
||||
{
|
||||
_old_follow_playhead = _editor->follow_playhead ();
|
||||
|
||||
if (ev->button == 1) {
|
||||
|
||||
pair<double, double> xr;
|
||||
|
|
@ -331,7 +333,6 @@ EditorSummary::on_button_press_event (GdkEventButton* ev)
|
|||
_zoom_position = get_position (ev->x, ev->y);
|
||||
_zoom_dragging = true;
|
||||
_editor->_dragging_playhead = true;
|
||||
_old_follow_playhead = _editor->follow_playhead ();
|
||||
_editor->set_follow_playhead (false);
|
||||
|
||||
if (suspending_editor_updates ()) {
|
||||
|
|
@ -361,7 +362,6 @@ EditorSummary::on_button_press_event (GdkEventButton* ev)
|
|||
_move_dragging = true;
|
||||
_moved = false;
|
||||
_editor->_dragging_playhead = true;
|
||||
_old_follow_playhead = _editor->follow_playhead ();
|
||||
_editor->set_follow_playhead (false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,17 +127,13 @@ ExportDialog::init ()
|
|||
/* Buttons */
|
||||
|
||||
cancel_button = add_button (Gtk::Stock::CANCEL, RESPONSE_CANCEL);
|
||||
// Realtime export is disabled for now, as it will most probably not work
|
||||
//rt_export_button = add_button (_("Realtime Export"), RESPONSE_RT);
|
||||
//fast_export_button = add_button (_("Fast Export"), RESPONSE_FAST);
|
||||
fast_export_button = add_button (_("Export"), RESPONSE_FAST);
|
||||
export_button = add_button (_("Export"), RESPONSE_FAST);
|
||||
set_default_response (RESPONSE_FAST);
|
||||
|
||||
list_files_button.set_name ("PaddedButton");
|
||||
|
||||
cancel_button->signal_clicked().connect (sigc::mem_fun (*this, &ExportDialog::close_dialog));
|
||||
//rt_export_button->signal_clicked().connect (sigc::mem_fun (*this, &ExportDialog::export_rt));
|
||||
fast_export_button->signal_clicked().connect (sigc::mem_fun (*this, &ExportDialog::export_fw));
|
||||
export_button->signal_clicked().connect (sigc::mem_fun (*this, &ExportDialog::do_export));
|
||||
|
||||
/* Done! */
|
||||
|
||||
|
|
@ -262,8 +258,7 @@ ExportDialog::update_warnings_and_example_filename ()
|
|||
list_files_hbox.hide ();
|
||||
list_files_string = "";
|
||||
|
||||
fast_export_button->set_sensitive (true);
|
||||
//rt_export_button->set_sensitive (true);
|
||||
export_button->set_sensitive (true);
|
||||
|
||||
/* Add new warnings */
|
||||
|
||||
|
|
@ -307,18 +302,10 @@ ExportDialog::show_conflicting_files ()
|
|||
}
|
||||
|
||||
void
|
||||
ExportDialog::export_rt ()
|
||||
ExportDialog::do_export ()
|
||||
{
|
||||
profile_manager->prepare_for_export ();
|
||||
handler->do_export (true);
|
||||
show_progress ();
|
||||
}
|
||||
|
||||
void
|
||||
ExportDialog::export_fw ()
|
||||
{
|
||||
profile_manager->prepare_for_export ();
|
||||
handler->do_export (false);
|
||||
handler->do_export ();
|
||||
show_progress ();
|
||||
}
|
||||
|
||||
|
|
@ -328,8 +315,7 @@ ExportDialog::show_progress ()
|
|||
status->running = true;
|
||||
|
||||
cancel_button->set_label (_("Stop Export"));
|
||||
//rt_export_button->set_sensitive (false);
|
||||
fast_export_button->set_sensitive (false);
|
||||
export_button->set_sensitive (false);
|
||||
|
||||
progress_bar.set_fraction (0.0);
|
||||
warning_widget.hide_all();
|
||||
|
|
@ -381,8 +367,7 @@ ExportDialog::progress_timeout ()
|
|||
void
|
||||
ExportDialog::add_error (string const & text)
|
||||
{
|
||||
fast_export_button->set_sensitive (false);
|
||||
//rt_export_button->set_sensitive (false);
|
||||
export_button->set_sensitive (false);
|
||||
|
||||
if (warn_string.empty()) {
|
||||
warn_string = _("<span color=\"#ffa755\">Error: ") + text + "</span>";
|
||||
|
|
|
|||
|
|
@ -102,8 +102,7 @@ class ExportDialog : public ArdourDialog {
|
|||
void update_warnings_and_example_filename ();
|
||||
void show_conflicting_files ();
|
||||
|
||||
void export_rt ();
|
||||
void export_fw ();
|
||||
void do_export ();
|
||||
|
||||
void show_progress ();
|
||||
gint progress_timeout ();
|
||||
|
|
@ -143,8 +142,7 @@ class ExportDialog : public ArdourDialog {
|
|||
/* Buttons */
|
||||
|
||||
Gtk::Button * cancel_button;
|
||||
Gtk::Button * rt_export_button;
|
||||
Gtk::Button * fast_export_button;
|
||||
Gtk::Button * export_button;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -115,10 +115,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
|
|||
_note_group->raise_to_top();
|
||||
PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
|
||||
|
||||
/* Look up MIDNAM details from our MidiTimeAxisView */
|
||||
MidiTimeAxisView& mtv = dynamic_cast<MidiTimeAxisView&> (tv);
|
||||
midi_patch_settings_changed (mtv.midi_patch_model (), mtv.midi_patch_custom_device_node ());
|
||||
|
||||
Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
|
||||
connect_to_diskstream ();
|
||||
|
||||
|
|
@ -156,10 +152,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
|
|||
_note_group->raise_to_top();
|
||||
PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
|
||||
|
||||
/* Look up MIDNAM details from our MidiTimeAxisView */
|
||||
MidiTimeAxisView& mtv = dynamic_cast<MidiTimeAxisView&> (tv);
|
||||
midi_patch_settings_changed (mtv.midi_patch_model (), mtv.midi_patch_custom_device_node ());
|
||||
|
||||
connect_to_diskstream ();
|
||||
|
||||
SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
|
||||
|
|
@ -273,8 +265,6 @@ MidiRegionView::init (Gdk::Color const & basic_color, bool wfd)
|
|||
region_resized (ARDOUR::bounds_change);
|
||||
region_locked ();
|
||||
|
||||
reset_width_dependent_items (_pixel_width);
|
||||
|
||||
set_colors ();
|
||||
|
||||
_enable_display = true;
|
||||
|
|
@ -284,6 +274,8 @@ MidiRegionView::init (Gdk::Color const & basic_color, bool wfd)
|
|||
}
|
||||
}
|
||||
|
||||
reset_width_dependent_items (_pixel_width);
|
||||
|
||||
group->raise_to_top();
|
||||
group->signal_event().connect(
|
||||
sigc::mem_fun(this, &MidiRegionView::canvas_event), false);
|
||||
|
|
@ -291,8 +283,8 @@ MidiRegionView::init (Gdk::Color const & basic_color, bool wfd)
|
|||
midi_view()->signal_channel_mode_changed().connect(
|
||||
sigc::mem_fun(this, &MidiRegionView::midi_channel_mode_changed));
|
||||
|
||||
midi_view()->signal_midi_patch_settings_changed().connect(
|
||||
sigc::mem_fun(this, &MidiRegionView::midi_patch_settings_changed));
|
||||
instrument_info().Changed.connect (_instrument_changed_connection, invalidator (*this),
|
||||
boost::bind (&MidiRegionView::instrument_settings_changed, this), gui_context());
|
||||
|
||||
trackview.editor().SnapChanged.connect(snap_changed_connection, invalidator(*this),
|
||||
boost::bind (&MidiRegionView::snap_changed, this),
|
||||
|
|
@ -304,6 +296,13 @@ MidiRegionView::init (Gdk::Color const & basic_color, bool wfd)
|
|||
SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
|
||||
}
|
||||
|
||||
InstrumentInfo&
|
||||
MidiRegionView::instrument_info () const
|
||||
{
|
||||
RouteUI* route_ui = dynamic_cast<RouteUI*> (&trackview);
|
||||
return route_ui->route()->instrument_info();
|
||||
}
|
||||
|
||||
const boost::shared_ptr<ARDOUR::MidiRegion>
|
||||
MidiRegionView::midi_region() const
|
||||
{
|
||||
|
|
@ -1209,20 +1208,8 @@ MidiRegionView::display_patch_changes_on_channel (uint8_t channel, bool active_c
|
|||
continue;
|
||||
}
|
||||
|
||||
MIDI::Name::PatchPrimaryKey patch_key ((*i)->bank_msb (), (*i)->bank_lsb (), (*i)->program ());
|
||||
|
||||
boost::shared_ptr<MIDI::Name::Patch> patch =
|
||||
MIDI::Name::MidiPatchManager::instance().find_patch(
|
||||
_model_name, _custom_device_mode, channel, patch_key);
|
||||
|
||||
if (patch != 0) {
|
||||
add_canvas_patch_change (*i, patch->name(), active_channel);
|
||||
} else {
|
||||
char buf[16];
|
||||
/* program and bank numbers are zero-based: convert to one-based: MIDI_BP_ZERO */
|
||||
snprintf (buf, 16, "%d %d", (*i)->program() + MIDI_BP_ZERO , (*i)->bank() + MIDI_BP_ZERO);
|
||||
add_canvas_patch_change (*i, buf, active_channel);
|
||||
}
|
||||
string patch_name = instrument_info().get_patch_name ((*i)->bank(), (*i)->program(), channel);
|
||||
add_canvas_patch_change (*i, patch_name, active_channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1360,6 +1347,14 @@ MidiRegionView::reset_width_dependent_items (double pixel_width)
|
|||
redisplay_model();
|
||||
}
|
||||
|
||||
for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) {
|
||||
if ((*x)->width() >= _pixel_width) {
|
||||
(*x)->hide();
|
||||
} else {
|
||||
(*x)->show();
|
||||
}
|
||||
}
|
||||
|
||||
move_step_edit_cursor (_step_edit_cursor_position);
|
||||
set_step_edit_cursor_width (_step_edit_cursor_width);
|
||||
}
|
||||
|
|
@ -1807,24 +1802,33 @@ MidiRegionView::add_canvas_patch_change (MidiModel::PatchChangePtr patch, const
|
|||
displaytext,
|
||||
height,
|
||||
x, 1.0,
|
||||
_model_name,
|
||||
_custom_device_mode,
|
||||
instrument_info(),
|
||||
patch,
|
||||
active_channel)
|
||||
);
|
||||
|
||||
if (patch_change->width() < _pixel_width) {
|
||||
// Show unless patch change is beyond the region bounds
|
||||
if (region_frames < 0 || region_frames >= _region->length()) {
|
||||
patch_change->hide();
|
||||
} else {
|
||||
patch_change->show();
|
||||
}
|
||||
} else {
|
||||
patch_change->hide ();
|
||||
}
|
||||
|
||||
_patch_changes.push_back (patch_change);
|
||||
}
|
||||
|
||||
MIDI::Name::PatchPrimaryKey
|
||||
MidiRegionView::patch_change_to_patch_key (MidiModel::PatchChangePtr p)
|
||||
{
|
||||
return MIDI::Name::PatchPrimaryKey (p->program(), p->bank());
|
||||
}
|
||||
|
||||
void
|
||||
MidiRegionView::get_patch_key_at (Evoral::MusicalTime time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key)
|
||||
MidiRegionView::get_patch_key_at (double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key)
|
||||
{
|
||||
MidiModel::PatchChanges::iterator i = _model->patch_change_lower_bound (time);
|
||||
while (i != _model->patch_changes().end() && (*i)->channel() != channel) {
|
||||
|
|
@ -1832,17 +1836,15 @@ MidiRegionView::get_patch_key_at (Evoral::MusicalTime time, uint8_t channel, MID
|
|||
}
|
||||
|
||||
if (i != _model->patch_changes().end()) {
|
||||
key.msb = (*i)->bank_msb ();
|
||||
key.lsb = (*i)->bank_lsb ();
|
||||
key.bank_number = (*i)->bank();
|
||||
key.program_number = (*i)->program ();
|
||||
} else {
|
||||
key.msb = key.lsb = key.program_number = 0;
|
||||
key.bank_number = key.program_number = 0;
|
||||
}
|
||||
|
||||
assert (key.is_sane());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MidiRegionView::change_patch_change (CanvasPatchChange& pc, const MIDI::Name::PatchPrimaryKey& new_patch)
|
||||
{
|
||||
|
|
@ -1852,7 +1854,7 @@ MidiRegionView::change_patch_change (CanvasPatchChange& pc, const MIDI::Name::Pa
|
|||
c->change_program (pc.patch (), new_patch.program_number);
|
||||
}
|
||||
|
||||
int const new_bank = (new_patch.msb << 7) | new_patch.lsb;
|
||||
int const new_bank = new_patch.bank_number;
|
||||
if (pc.patch()->bank() != new_bank) {
|
||||
c->change_bank (pc.patch (), new_bank);
|
||||
}
|
||||
|
|
@ -1941,8 +1943,7 @@ void
|
|||
MidiRegionView::previous_patch (CanvasPatchChange& patch)
|
||||
{
|
||||
if (patch.patch()->program() < 127) {
|
||||
MIDI::Name::PatchPrimaryKey key;
|
||||
get_patch_key_at (patch.patch()->time(), patch.patch()->channel(), key);
|
||||
MIDI::Name::PatchPrimaryKey key = patch_change_to_patch_key (patch.patch());
|
||||
key.program_number++;
|
||||
change_patch_change (patch, key);
|
||||
}
|
||||
|
|
@ -1952,8 +1953,7 @@ void
|
|||
MidiRegionView::next_patch (CanvasPatchChange& patch)
|
||||
{
|
||||
if (patch.patch()->program() > 0) {
|
||||
MIDI::Name::PatchPrimaryKey key;
|
||||
get_patch_key_at (patch.patch()->time(), patch.patch()->channel(), key);
|
||||
MIDI::Name::PatchPrimaryKey key = patch_change_to_patch_key (patch.patch());
|
||||
key.program_number--;
|
||||
change_patch_change (patch, key);
|
||||
}
|
||||
|
|
@ -1963,17 +1963,10 @@ void
|
|||
MidiRegionView::previous_bank (CanvasPatchChange& patch)
|
||||
{
|
||||
if (patch.patch()->program() < 127) {
|
||||
MIDI::Name::PatchPrimaryKey key;
|
||||
get_patch_key_at (patch.patch()->time(), patch.patch()->channel(), key);
|
||||
if (key.lsb > 0) {
|
||||
key.lsb--;
|
||||
MIDI::Name::PatchPrimaryKey key = patch_change_to_patch_key (patch.patch());
|
||||
if (key.bank_number > 0) {
|
||||
key.bank_number--;
|
||||
change_patch_change (patch, key);
|
||||
} else {
|
||||
if (key.msb > 0) {
|
||||
key.lsb = 127;
|
||||
key.msb--;
|
||||
change_patch_change (patch, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1982,17 +1975,10 @@ void
|
|||
MidiRegionView::next_bank (CanvasPatchChange& patch)
|
||||
{
|
||||
if (patch.patch()->program() > 0) {
|
||||
MIDI::Name::PatchPrimaryKey key;
|
||||
get_patch_key_at (patch.patch()->time(), patch.patch()->channel(), key);
|
||||
if (key.lsb < 127) {
|
||||
key.lsb++;
|
||||
MIDI::Name::PatchPrimaryKey key = patch_change_to_patch_key (patch.patch());
|
||||
if (key.bank_number < 127) {
|
||||
key.bank_number++;
|
||||
change_patch_change (patch, key);
|
||||
} else {
|
||||
if (key.msb < 127) {
|
||||
key.lsb = 0;
|
||||
key.msb++;
|
||||
change_patch_change (patch, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2905,7 +2891,7 @@ void
|
|||
MidiRegionView::change_velocities (bool up, bool fine, bool allow_smush, bool all_together)
|
||||
{
|
||||
int8_t delta;
|
||||
int8_t value;
|
||||
int8_t value = 0;
|
||||
|
||||
if (_selection.empty()) {
|
||||
return;
|
||||
|
|
@ -3230,10 +3216,8 @@ MidiRegionView::midi_channel_mode_changed(ChannelMode mode, uint16_t mask)
|
|||
}
|
||||
|
||||
void
|
||||
MidiRegionView::midi_patch_settings_changed(std::string model, std::string custom_device_mode)
|
||||
MidiRegionView::instrument_settings_changed ()
|
||||
{
|
||||
_model_name = model;
|
||||
_custom_device_mode = custom_device_mode;
|
||||
redisplay_model();
|
||||
}
|
||||
|
||||
|
|
@ -3739,7 +3723,7 @@ MidiRegionView::trim_front_ending ()
|
|||
void
|
||||
MidiRegionView::edit_patch_change (ArdourCanvas::CanvasPatchChange* pc)
|
||||
{
|
||||
PatchChangeDialog d (&_source_relative_time_converter, trackview.session(), *pc->patch (), _model_name, _custom_device_mode, Gtk::Stock::APPLY);
|
||||
PatchChangeDialog d (&_source_relative_time_converter, trackview.session(), *pc->patch (), instrument_info(), Gtk::Stock::APPLY);
|
||||
if (d.run () != Gtk::RESPONSE_ACCEPT) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,11 @@ public:
|
|||
* @key a reference to an instance of MIDI::Name::PatchPrimaryKey whose fields will
|
||||
* will be set according to the result of the lookup
|
||||
*/
|
||||
void get_patch_key_at(double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key);
|
||||
void get_patch_key_at (double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key);
|
||||
|
||||
/** Convert a given PatchChange into a PatchPrimaryKey
|
||||
*/
|
||||
MIDI::Name::PatchPrimaryKey patch_change_to_patch_key (ARDOUR::MidiModel::PatchChangePtr);
|
||||
|
||||
/** Change old_patch to new_patch.
|
||||
* @param old_patch the canvas patch change which is to be altered
|
||||
|
|
@ -281,6 +285,11 @@ public:
|
|||
|
||||
void show_list_editor ();
|
||||
|
||||
typedef std::set<ArdourCanvas::CanvasNoteEvent*> Selection;
|
||||
Selection selection () const {
|
||||
return _selection;
|
||||
}
|
||||
|
||||
void selection_as_notelist (Notes& selected, bool allow_all_if_none_selected = false);
|
||||
|
||||
void enable_display (bool);
|
||||
|
|
@ -295,13 +304,7 @@ public:
|
|||
|
||||
void clear_selection (bool signal = true) { clear_selection_except (0, signal); }
|
||||
|
||||
std::string model_name () const {
|
||||
return _model_name;
|
||||
}
|
||||
|
||||
std::string custom_device_mode () const {
|
||||
return _custom_device_mode;
|
||||
}
|
||||
ARDOUR::InstrumentInfo& instrument_info() const;
|
||||
|
||||
protected:
|
||||
/** Allows derived types to specify their visibility requirements
|
||||
|
|
@ -351,7 +354,8 @@ private:
|
|||
bool note_canvas_event(GdkEvent* ev);
|
||||
|
||||
void midi_channel_mode_changed(ARDOUR::ChannelMode mode, uint16_t mask);
|
||||
void midi_patch_settings_changed(std::string model, std::string custom_device_mode);
|
||||
void instrument_settings_changed ();
|
||||
PBD::ScopedConnection _instrument_changed_connection;
|
||||
|
||||
void change_note_channel (ArdourCanvas::CanvasNoteEvent *, int8_t, bool relative=false);
|
||||
void change_note_velocity(ArdourCanvas::CanvasNoteEvent* ev, int8_t vel, bool relative=false);
|
||||
|
|
@ -375,12 +379,6 @@ private:
|
|||
uint8_t _current_range_min;
|
||||
uint8_t _current_range_max;
|
||||
|
||||
/// MIDNAM information of the current track: Model name of MIDNAM file
|
||||
std::string _model_name;
|
||||
|
||||
/// MIDNAM information of the current track: CustomDeviceMode
|
||||
std::string _custom_device_mode;
|
||||
|
||||
typedef std::list<ArdourCanvas::CanvasNoteEvent*> Events;
|
||||
typedef std::vector< boost::shared_ptr<ArdourCanvas::CanvasPatchChange> > PatchChanges;
|
||||
typedef std::vector< boost::shared_ptr<ArdourCanvas::CanvasSysEx> > SysExes;
|
||||
|
|
@ -409,8 +407,7 @@ private:
|
|||
MouseState _mouse_state;
|
||||
int _pressed_button;
|
||||
|
||||
typedef std::set<ArdourCanvas::CanvasNoteEvent*> Selection;
|
||||
/// Currently selected CanvasNoteEvents
|
||||
/** Currently selected CanvasNoteEvents */
|
||||
Selection _selection;
|
||||
|
||||
bool _sort_needed;
|
||||
|
|
|
|||
|
|
@ -165,12 +165,4 @@ void
|
|||
MidiScroomer::on_size_request(Gtk::Requisition* r)
|
||||
{
|
||||
r->width = 12;
|
||||
r->height = 100;
|
||||
}
|
||||
|
||||
void
|
||||
MidiScroomer::on_size_allocate(Gtk::Allocation& a)
|
||||
{
|
||||
Scroomer::on_size_allocate(a);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ class MidiScroomer : public Gtkmm2ext::Scroomer {
|
|||
|
||||
bool on_expose_event(GdkEventExpose*);
|
||||
void on_size_request(Gtk::Requisition*);
|
||||
void on_size_allocate(Gtk::Allocation&);
|
||||
|
||||
void get_colors(double color[], Component comp);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "ardour/midi_region.h"
|
||||
#include "ardour/midi_source.h"
|
||||
#include "ardour/midi_track.h"
|
||||
#include "ardour/operations.h"
|
||||
#include "ardour/region_factory.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/smf_source.h"
|
||||
|
|
@ -156,6 +157,11 @@ MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wfd,
|
|||
/* display events and find note range */
|
||||
display_region (region_view, wfd);
|
||||
|
||||
/* fit note range if we are importing */
|
||||
if (_trackview.session()->operation_in_progress (Operations::insert_file)) {
|
||||
set_note_range (ContentsRange);
|
||||
}
|
||||
|
||||
/* catch regionview going away */
|
||||
region->DropReferences.connect (*this, invalidator (*this), boost::bind (&MidiStreamView::remove_region_view, this, region), gui_context());
|
||||
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
|
|||
midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()), atoi (gui_property ("note-range-max").c_str()), true);
|
||||
}
|
||||
midi_view()->NoteRangeChanged.connect (sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
|
||||
_view->ContentsHeightChanged.connect (sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
|
||||
|
||||
ignore_toggle = false;
|
||||
|
||||
|
|
@ -171,8 +172,19 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
|
|||
_range_scroomer->DragStarting.connect (sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
|
||||
_range_scroomer->DragFinishing.connect (sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
|
||||
|
||||
controls_hbox.pack_start(*_range_scroomer);
|
||||
controls_hbox.pack_start(*_piano_roll_header);
|
||||
/* Put the scroomer and the keyboard in a VBox with a padding
|
||||
label so that they can be reduced in height for stacked-view
|
||||
tracks.
|
||||
*/
|
||||
VBox* v = manage (new VBox);
|
||||
HBox* h = manage (new HBox);
|
||||
h->pack_start (*_range_scroomer);
|
||||
h->pack_start (*_piano_roll_header);
|
||||
v->pack_start (*h, false, false);
|
||||
v->pack_start (*manage (new Label ("")), true, true);
|
||||
v->show ();
|
||||
h->show ();
|
||||
controls_hbox.pack_start(*v);
|
||||
|
||||
controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
|
||||
controls_base_selected_name = "MidiTrackControlsBaseSelected";
|
||||
|
|
@ -208,8 +220,12 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
|
|||
_model_selector.set_active_text (gui_property (X_("midnam-model-name")));
|
||||
_custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
|
||||
|
||||
ARDOUR_UI::instance()->set_tip (_model_selector, _("External MIDI Device"));
|
||||
ARDOUR_UI::instance()->set_tip (_custom_device_mode_selector, _("External Device Mode"));
|
||||
|
||||
midi_controls_hbox->pack_start(_channel_selector, true, false);
|
||||
if (!patch_manager.all_models().empty()) {
|
||||
_midi_controls_box.set_border_width (5);
|
||||
_midi_controls_box.pack_start(_model_selector, true, false);
|
||||
_midi_controls_box.pack_start(_custom_device_mode_selector, true, false);
|
||||
}
|
||||
|
|
@ -318,14 +334,13 @@ MidiTimeAxisView::model_changed()
|
|||
|
||||
_custom_device_mode_selector.set_active(0);
|
||||
|
||||
set_gui_property (X_("midnam-model-name"), midi_patch_model ());
|
||||
_route->instrument_info().set_external_instrument (_model_selector.get_active_text(), _custom_device_mode_selector.get_active_text());
|
||||
}
|
||||
|
||||
void
|
||||
MidiTimeAxisView::custom_device_mode_changed()
|
||||
{
|
||||
_midi_patch_settings_changed.emit (midi_patch_model (), midi_patch_custom_device_node ());
|
||||
set_gui_property (X_("midnam-custom-device-mode"), midi_patch_custom_device_node ());
|
||||
_route->instrument_info().set_external_instrument (_model_selector.get_active_text(), _custom_device_mode_selector.get_active_text());
|
||||
}
|
||||
|
||||
MidiStreamView*
|
||||
|
|
@ -381,11 +396,11 @@ MidiTimeAxisView::append_extra_display_menu_items ()
|
|||
|
||||
range_items.push_back (MenuElem (_("Show Full Range"), sigc::bind (
|
||||
sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
|
||||
MidiStreamView::FullRange)));
|
||||
MidiStreamView::FullRange, true)));
|
||||
|
||||
range_items.push_back (MenuElem (_("Fit Contents"), sigc::bind (
|
||||
sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
|
||||
MidiStreamView::ContentsRange)));
|
||||
MidiStreamView::ContentsRange, true)));
|
||||
|
||||
items.push_back (MenuElem (_("Note Range"), *range_menu));
|
||||
items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
|
||||
|
|
@ -727,13 +742,13 @@ MidiTimeAxisView::build_note_mode_menu()
|
|||
mode_menu->set_name ("ArdourContextMenu");
|
||||
|
||||
RadioMenuItem::Group mode_group;
|
||||
items.push_back (RadioMenuElem (mode_group, _("Sustained"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained)));
|
||||
items.push_back (RadioMenuElem (mode_group,_("Sustained"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Sustained, true)));
|
||||
_note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
_note_mode_item->set_active(_note_mode == Sustained);
|
||||
|
||||
items.push_back (RadioMenuElem (mode_group, _("Percussive"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive)));
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussive, true)));
|
||||
_percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
_percussion_mode_item->set_active(_note_mode == Percussive);
|
||||
|
||||
|
|
@ -752,19 +767,19 @@ MidiTimeAxisView::build_color_mode_menu()
|
|||
RadioMenuItem::Group mode_group;
|
||||
items.push_back (RadioMenuElem (mode_group, _("Meter Colors"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
|
||||
MeterColors, false, true)));
|
||||
MeterColors, false, true, true)));
|
||||
_meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
_meter_color_mode_item->set_active(_color_mode == MeterColors);
|
||||
|
||||
items.push_back (RadioMenuElem (mode_group, _("Channel Colors"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
|
||||
ChannelColors, false, true)));
|
||||
ChannelColors, false, true, true)));
|
||||
_channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
_channel_color_mode_item->set_active(_color_mode == ChannelColors);
|
||||
|
||||
items.push_back (RadioMenuElem (mode_group, _("Track Color"),
|
||||
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
|
||||
TrackColor, false, true)));
|
||||
TrackColor, false, true, true)));
|
||||
_channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
|
||||
_channel_color_mode_item->set_active(_color_mode == TrackColor);
|
||||
|
||||
|
|
@ -772,19 +787,29 @@ MidiTimeAxisView::build_color_mode_menu()
|
|||
}
|
||||
|
||||
void
|
||||
MidiTimeAxisView::set_note_mode(NoteMode mode)
|
||||
MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
|
||||
{
|
||||
if (apply_to_selection) {
|
||||
_editor.get_selection().tracks.foreach_midi_time_axis (boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
|
||||
} else {
|
||||
if (_note_mode != mode || midi_track()->note_mode() != mode) {
|
||||
_note_mode = mode;
|
||||
midi_track()->set_note_mode(mode);
|
||||
set_gui_property ("note-mode", enum_2_string(_note_mode));
|
||||
_view->redisplay_track();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay)
|
||||
MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
|
||||
{
|
||||
if (apply_to_selection) {
|
||||
_editor.get_selection().tracks.foreach_midi_time_axis (
|
||||
boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false)
|
||||
);
|
||||
} else {
|
||||
|
||||
if (_color_mode == mode && !force) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -800,16 +825,23 @@ MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay)
|
|||
if (redisplay) {
|
||||
_view->redisplay_track();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MidiTimeAxisView::set_note_range(MidiStreamView::VisibleNoteRange range)
|
||||
MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
|
||||
{
|
||||
if (!_ignore_signals)
|
||||
if (apply_to_selection) {
|
||||
_editor.get_selection().tracks.foreach_midi_time_axis (
|
||||
boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false)
|
||||
);
|
||||
} else {
|
||||
if (!_ignore_signals) {
|
||||
midi_view()->set_note_range(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MidiTimeAxisView::update_range()
|
||||
{
|
||||
|
|
@ -1207,14 +1239,8 @@ MidiTimeAxisView::note_range_changed ()
|
|||
set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
|
||||
}
|
||||
|
||||
string
|
||||
MidiTimeAxisView::midi_patch_model () const
|
||||
void
|
||||
MidiTimeAxisView::contents_height_changed ()
|
||||
{
|
||||
return _model_selector.get_active_text ();
|
||||
}
|
||||
|
||||
string
|
||||
MidiTimeAxisView::midi_patch_custom_device_node () const
|
||||
{
|
||||
return _custom_device_mode_selector.get_active_text ();
|
||||
_range_scroomer->set_size_request (-1, _view->child_height ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,11 +86,6 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
|||
return _channel_selector.mode_changed;
|
||||
}
|
||||
|
||||
sigc::signal<void, std::string, std::string>& signal_midi_patch_settings_changed() {
|
||||
return _midi_patch_settings_changed;
|
||||
}
|
||||
|
||||
|
||||
const MidiMultipleChannelSelector& channel_selector() { return _channel_selector; }
|
||||
|
||||
Gtk::CheckMenuItem* automation_child_menu_item (Evoral::Parameter);
|
||||
|
|
@ -102,9 +97,6 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
|||
|
||||
uint8_t get_channel_for_add () const;
|
||||
|
||||
std::string midi_patch_model () const;
|
||||
std::string midi_patch_custom_device_node () const;
|
||||
|
||||
protected:
|
||||
void start_step_editing ();
|
||||
void stop_step_editing ();
|
||||
|
|
@ -120,12 +112,13 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
|||
Gtk::Menu* build_note_mode_menu();
|
||||
Gtk::Menu* build_color_mode_menu();
|
||||
|
||||
void set_note_mode (ARDOUR::NoteMode mode);
|
||||
void set_color_mode (ARDOUR::ColorMode, bool force=false, bool redisplay=true);
|
||||
void set_note_range(MidiStreamView::VisibleNoteRange range);
|
||||
void set_note_mode (ARDOUR::NoteMode mode, bool apply_to_selection = false);
|
||||
void set_color_mode (ARDOUR::ColorMode, bool force = false, bool redisplay = true, bool apply_to_selection = false);
|
||||
void set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection = false);
|
||||
|
||||
void route_active_changed ();
|
||||
void note_range_changed ();
|
||||
void contents_height_changed ();
|
||||
|
||||
bool _ignore_signals;
|
||||
MidiScroomer* _range_scroomer;
|
||||
|
|
|
|||
|
|
@ -1551,6 +1551,18 @@ Mixer_UI::on_key_press_event (GdkEventKey* ev)
|
|||
|
||||
KeyboardKey k (ev->state, ev->keyval);
|
||||
|
||||
GtkAccelKey key;
|
||||
|
||||
/* Handle toggle-mixer-on-top here, so it can do a different thing if the
|
||||
mixer is already on top and received this key press.
|
||||
*/
|
||||
if (gtk_accel_map_lookup_entry("<Actions>/Common/toggle-mixer-on-top", &key)) {
|
||||
if (int (k.state()) == key.accel_mods && k.key() == key.accel_key) {
|
||||
ARDOUR_UI::instance()->goto_editor_window();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bindings.activate (k, Bindings::Press)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "gtkmm2ext/gtk_ui.h"
|
||||
#include "gtkmm2ext/keyboard.h"
|
||||
#include "gtkmm2ext/utils.h"
|
||||
#include "gtkmm2ext/persistent_tooltip.h"
|
||||
|
||||
#include "ardour/pannable.h"
|
||||
#include "ardour/panner.h"
|
||||
|
|
@ -64,6 +65,7 @@ MonoPanner::MonoPanner (boost::shared_ptr<ARDOUR::Panner> panner)
|
|||
, accumulated_delta (0)
|
||||
, detented (false)
|
||||
, position_binder (position_control)
|
||||
, _dragging (false)
|
||||
{
|
||||
if (!have_colors) {
|
||||
set_colors ();
|
||||
|
|
@ -73,6 +75,8 @@ MonoPanner::MonoPanner (boost::shared_ptr<ARDOUR::Panner> panner)
|
|||
position_control->Changed.connect (connections, invalidator(*this), boost::bind (&MonoPanner::value_change, this), gui_context());
|
||||
|
||||
ColorsChanged.connect (sigc::mem_fun (*this, &MonoPanner::color_handler));
|
||||
|
||||
set_tooltip ();
|
||||
}
|
||||
|
||||
MonoPanner::~MonoPanner ()
|
||||
|
|
@ -81,12 +85,8 @@ MonoPanner::~MonoPanner ()
|
|||
}
|
||||
|
||||
void
|
||||
MonoPanner::set_drag_data ()
|
||||
MonoPanner::set_tooltip ()
|
||||
{
|
||||
if (!_drag_data_label) {
|
||||
return;
|
||||
}
|
||||
|
||||
double pos = position_control->get_value(); // 0..1
|
||||
|
||||
/* We show the position of the center of the image relative to the left & right.
|
||||
|
|
@ -101,7 +101,7 @@ MonoPanner::set_drag_data ()
|
|||
snprintf (buf, sizeof (buf), "L:%3d R:%3d",
|
||||
(int) rint (100.0 * (1.0 - pos)),
|
||||
(int) rint (100.0 * pos));
|
||||
_drag_data_label->set_markup (buf);
|
||||
_tooltip.set_tip (buf);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -255,6 +255,7 @@ MonoPanner::on_button_press_event (GdkEventButton* ev)
|
|||
last_drag_x = ev->x;
|
||||
|
||||
_dragging = false;
|
||||
_tooltip.target_stop_drag ();
|
||||
accumulated_delta = 0;
|
||||
detented = false;
|
||||
|
||||
|
|
@ -290,6 +291,7 @@ MonoPanner::on_button_press_event (GdkEventButton* ev)
|
|||
}
|
||||
|
||||
_dragging = false;
|
||||
_tooltip.target_stop_drag ();
|
||||
|
||||
} else if (ev->type == GDK_BUTTON_PRESS) {
|
||||
|
||||
|
|
@ -299,8 +301,8 @@ MonoPanner::on_button_press_event (GdkEventButton* ev)
|
|||
}
|
||||
|
||||
_dragging = true;
|
||||
_tooltip.target_start_drag ();
|
||||
StartGesture ();
|
||||
show_drag_data_window ();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -318,11 +320,10 @@ MonoPanner::on_button_release_event (GdkEventButton* ev)
|
|||
}
|
||||
|
||||
_dragging = false;
|
||||
_tooltip.target_stop_drag ();
|
||||
accumulated_delta = 0;
|
||||
detented = false;
|
||||
|
||||
hide_drag_data_window ();
|
||||
|
||||
if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
|
||||
_panner->reset ();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class MonoPanner : public PannerInterface
|
|||
|
||||
BindingProxy position_binder;
|
||||
|
||||
void set_drag_data ();
|
||||
void set_tooltip ();
|
||||
|
||||
struct ColorScheme {
|
||||
uint32_t outline;
|
||||
|
|
@ -74,6 +74,8 @@ class MonoPanner : public PannerInterface
|
|||
uint32_t pos_fill;
|
||||
};
|
||||
|
||||
bool _dragging;
|
||||
|
||||
static ColorScheme colors;
|
||||
static void set_colors ();
|
||||
static bool have_colors;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <gtkmm.h>
|
||||
#include "gtkmm2ext/keyboard.h"
|
||||
#include "gtkmm2ext/persistent_tooltip.h"
|
||||
#include "panner_interface.h"
|
||||
#include "panner_editor.h"
|
||||
#include "global_signals.h"
|
||||
|
|
@ -32,9 +33,7 @@ using namespace Gtkmm2ext;
|
|||
|
||||
PannerInterface::PannerInterface (boost::shared_ptr<Panner> p)
|
||||
: _panner (p)
|
||||
, _drag_data_window (0)
|
||||
, _drag_data_label (0)
|
||||
, _dragging (false)
|
||||
, _tooltip (this)
|
||||
, _editor (0)
|
||||
{
|
||||
set_flags (Gtk::CAN_FOCUS);
|
||||
|
|
@ -49,66 +48,14 @@ PannerInterface::PannerInterface (boost::shared_ptr<Panner> p)
|
|||
|
||||
PannerInterface::~PannerInterface ()
|
||||
{
|
||||
delete _drag_data_window;
|
||||
delete _editor;
|
||||
}
|
||||
|
||||
void
|
||||
PannerInterface::show_drag_data_window ()
|
||||
{
|
||||
if (!_drag_data_window) {
|
||||
_drag_data_window = new Window (WINDOW_POPUP);
|
||||
_drag_data_window->set_name (X_("ContrastingPopup"));
|
||||
_drag_data_window->set_position (WIN_POS_MOUSE);
|
||||
_drag_data_window->set_decorated (false);
|
||||
|
||||
_drag_data_label = manage (new Label);
|
||||
_drag_data_label->set_use_markup (true);
|
||||
|
||||
_drag_data_window->set_border_width (6);
|
||||
_drag_data_window->add (*_drag_data_label);
|
||||
_drag_data_label->show ();
|
||||
|
||||
Window* toplevel = dynamic_cast<Window*> (get_toplevel());
|
||||
if (toplevel) {
|
||||
_drag_data_window->set_transient_for (*toplevel);
|
||||
}
|
||||
}
|
||||
|
||||
set_drag_data ();
|
||||
|
||||
if (!_drag_data_window->is_visible ()) {
|
||||
/* move the window a little away from the mouse */
|
||||
int rx, ry;
|
||||
get_window()->get_origin (rx, ry);
|
||||
_drag_data_window->move (rx, ry + get_height());
|
||||
_drag_data_window->present ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PannerInterface::hide_drag_data_window ()
|
||||
{
|
||||
if (_drag_data_window) {
|
||||
_drag_data_window->hide ();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PannerInterface::on_enter_notify_event (GdkEventCrossing *)
|
||||
{
|
||||
grab_focus ();
|
||||
Keyboard::magic_widget_grab_focus ();
|
||||
|
||||
_drag_data_timeout = Glib::signal_timeout().connect (sigc::mem_fun (*this, &PannerInterface::drag_data_timeout), 500);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
PannerInterface::drag_data_timeout ()
|
||||
{
|
||||
show_drag_data_window ();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -116,12 +63,6 @@ bool
|
|||
PannerInterface::on_leave_notify_event (GdkEventCrossing *)
|
||||
{
|
||||
Keyboard::magic_widget_drop_focus ();
|
||||
|
||||
_drag_data_timeout.disconnect ();
|
||||
if (!_dragging) {
|
||||
hide_drag_data_window ();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +75,7 @@ PannerInterface::on_key_release_event (GdkEventKey*)
|
|||
void
|
||||
PannerInterface::value_change ()
|
||||
{
|
||||
set_drag_data ();
|
||||
set_tooltip ();
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
|
|
@ -167,3 +108,28 @@ PannerInterface::edit ()
|
|||
_editor = editor ();
|
||||
_editor->show ();
|
||||
}
|
||||
|
||||
PannerPersistentTooltip::PannerPersistentTooltip (Gtk::Widget* w)
|
||||
: PersistentTooltip (w)
|
||||
, _dragging (false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
PannerPersistentTooltip::target_start_drag ()
|
||||
{
|
||||
_dragging = true;
|
||||
}
|
||||
|
||||
void
|
||||
PannerPersistentTooltip::target_stop_drag ()
|
||||
{
|
||||
_dragging = false;
|
||||
}
|
||||
|
||||
bool
|
||||
PannerPersistentTooltip::dragging () const
|
||||
{
|
||||
return _dragging;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <boost/shared_ptr.hpp>
|
||||
#include <gtkmm/drawingarea.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include "gtkmm2ext/persistent_tooltip.h"
|
||||
#include "pbd/destructible.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
|
@ -31,6 +32,21 @@ namespace ARDOUR {
|
|||
|
||||
class PannerEditor;
|
||||
|
||||
class PannerPersistentTooltip : public Gtkmm2ext::PersistentTooltip
|
||||
{
|
||||
public:
|
||||
PannerPersistentTooltip (Gtk::Widget* w);
|
||||
|
||||
void target_start_drag ();
|
||||
void target_stop_drag ();
|
||||
|
||||
bool dragging () const;
|
||||
|
||||
private:
|
||||
bool _dragging;
|
||||
};
|
||||
|
||||
|
||||
/** Parent class for some panner UI classes that contains some common code */
|
||||
class PannerInterface : public Gtk::DrawingArea, public PBD::Destructible
|
||||
{
|
||||
|
|
@ -45,10 +61,8 @@ public:
|
|||
void edit ();
|
||||
|
||||
protected:
|
||||
virtual void set_drag_data () = 0;
|
||||
virtual void set_tooltip () = 0;
|
||||
|
||||
void show_drag_data_window ();
|
||||
void hide_drag_data_window ();
|
||||
void value_change ();
|
||||
|
||||
bool on_enter_notify_event (GdkEventCrossing *);
|
||||
|
|
@ -58,14 +72,9 @@ protected:
|
|||
bool on_button_release_event (GdkEventButton*);
|
||||
|
||||
boost::shared_ptr<ARDOUR::Panner> _panner;
|
||||
Gtk::Window* _drag_data_window;
|
||||
Gtk::Label* _drag_data_label;
|
||||
bool _dragging;
|
||||
PannerPersistentTooltip _tooltip;
|
||||
|
||||
private:
|
||||
bool drag_data_timeout ();
|
||||
sigc::connection _drag_data_timeout;
|
||||
|
||||
virtual PannerEditor* editor () = 0;
|
||||
PannerEditor* _editor;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,11 +20,18 @@
|
|||
|
||||
#include <gtkmm/stock.h>
|
||||
#include <gtkmm/table.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "gtkmm2ext/utils.h"
|
||||
|
||||
#include "ardour/midi_patch_manager.h"
|
||||
#include "ardour/beats_frames_converter.h"
|
||||
#include "ardour/instrument_info.h"
|
||||
|
||||
#include "patch_change_dialog.h"
|
||||
#include "gui_thread.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace std;
|
||||
|
|
@ -36,14 +43,12 @@ PatchChangeDialog::PatchChangeDialog (
|
|||
const ARDOUR::BeatsFramesConverter* tc,
|
||||
ARDOUR::Session* session,
|
||||
Evoral::PatchChange<Evoral::MusicalTime> const & patch,
|
||||
string const & model_name,
|
||||
string const & custom_device_node,
|
||||
ARDOUR::InstrumentInfo& info,
|
||||
const Gtk::BuiltinStockID& ok
|
||||
)
|
||||
: ArdourDialog (_("Patch Change"), true)
|
||||
, _time_converter (tc)
|
||||
, _model_name (model_name)
|
||||
, _custom_device_mode (custom_device_node)
|
||||
, _info (info)
|
||||
, _time (X_("patchchangetime"), true, "", true, false)
|
||||
, _channel (*manage (new Adjustment (1, 1, 16, 1, 4)))
|
||||
, _program (*manage (new Adjustment (1, 1, 128, 1, 16)))
|
||||
|
|
@ -115,9 +120,21 @@ PatchChangeDialog::PatchChangeDialog (
|
|||
set_active_bank_combo ();
|
||||
bank_combo_changed ();
|
||||
|
||||
_info.Changed.connect (_info_changed_connection, invalidator (*this),
|
||||
boost::bind (&PatchChangeDialog::instrument_info_changed, this), gui_context());
|
||||
|
||||
show_all ();
|
||||
}
|
||||
|
||||
void
|
||||
PatchChangeDialog::instrument_info_changed ()
|
||||
{
|
||||
_bank_combo.clear ();
|
||||
_patch_combo.clear ();
|
||||
fill_bank_combo ();
|
||||
fill_patch_combo ();
|
||||
}
|
||||
|
||||
Evoral::PatchChange<Evoral::MusicalTime>
|
||||
PatchChangeDialog::patch () const
|
||||
{
|
||||
|
|
@ -139,12 +156,13 @@ PatchChangeDialog::patch () const
|
|||
void
|
||||
PatchChangeDialog::fill_bank_combo ()
|
||||
{
|
||||
MIDI::Name::ChannelNameSet::PatchBanks const * banks = get_banks ();
|
||||
if (banks == 0) {
|
||||
boost::shared_ptr<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel.get_value_as_int() - 1);
|
||||
|
||||
if (!cns) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = banks->begin(); i != banks->end(); ++i) {
|
||||
for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) {
|
||||
string n = (*i)->name ();
|
||||
boost::replace_all (n, "_", " ");
|
||||
_bank_combo.append_text (n);
|
||||
|
|
@ -157,17 +175,18 @@ PatchChangeDialog::set_active_bank_combo ()
|
|||
{
|
||||
_current_patch_bank.reset ();
|
||||
|
||||
MIDI::Name::ChannelNameSet::PatchBanks const * banks = get_banks ();
|
||||
if (banks == 0) {
|
||||
boost::shared_ptr<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel.get_value_as_int() - 1);
|
||||
|
||||
if (!cns) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = banks->begin(); i != banks->end(); ++i) {
|
||||
for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) {
|
||||
|
||||
string n = (*i)->name ();
|
||||
boost::replace_all (n, "_", " ");
|
||||
|
||||
MIDI::Name::PatchPrimaryKey const * key = (*i)->patch_primary_key ();
|
||||
if (key && ((key->msb << 7) | key->lsb) == _bank.get_value () - 1) {
|
||||
if ((*i)->number() == _bank.get_value () - 1) {
|
||||
_current_patch_bank = *i;
|
||||
_ignore_signals = true;
|
||||
_bank_combo.set_active_text (n);
|
||||
|
|
@ -193,12 +212,13 @@ PatchChangeDialog::bank_combo_changed ()
|
|||
|
||||
_current_patch_bank.reset ();
|
||||
|
||||
MIDI::Name::ChannelNameSet::PatchBanks const * banks = get_banks ();
|
||||
if (banks == 0) {
|
||||
boost::shared_ptr<MIDI::Name::ChannelNameSet> cns = _info.get_patches (_channel.get_value_as_int() - 1);
|
||||
|
||||
if (!cns) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = banks->begin(); i != banks->end(); ++i) {
|
||||
for (MIDI::Name::ChannelNameSet::PatchBanks::const_iterator i = cns->patch_banks().begin(); i != cns->patch_banks().end(); ++i) {
|
||||
string n = (*i)->name ();
|
||||
boost::replace_all (n, "_", " ");
|
||||
if (n == _bank_combo.get_active_text()) {
|
||||
|
|
@ -215,12 +235,9 @@ PatchChangeDialog::bank_combo_changed ()
|
|||
fill_patch_combo ();
|
||||
set_active_patch_combo ();
|
||||
|
||||
MIDI::Name::PatchPrimaryKey const * key = _current_patch_bank->patch_primary_key ();
|
||||
if (key) {
|
||||
_ignore_signals = true;
|
||||
_bank.set_value (((key->msb << 7) | key->lsb) + 1);
|
||||
_bank.set_value (_current_patch_bank->number() + 1);
|
||||
_ignore_signals = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Fill the contents of the patch combo */
|
||||
|
|
@ -284,14 +301,17 @@ PatchChangeDialog::patch_combo_changed ()
|
|||
}
|
||||
|
||||
const MIDI::Name::PatchBank::PatchNameList& patches = _current_patch_bank->patch_name_list ();
|
||||
|
||||
for (MIDI::Name::PatchBank::PatchNameList::const_iterator j = patches.begin(); j != patches.end(); ++j) {
|
||||
string n = (*j)->name ();
|
||||
boost::replace_all (n, "_", " ");
|
||||
std::cerr << "Looking for " << n << " vs " << _patch_combo.get_active_text() << std::endl;
|
||||
if (n == _patch_combo.get_active_text ()) {
|
||||
MIDI::Name::PatchPrimaryKey const & key = (*j)->patch_primary_key ();
|
||||
_ignore_signals = true;
|
||||
_program.set_value (key.program_number + 1);
|
||||
std::cerr << " reset pgm number to " << (int) (*j)->program_number() << std::endl;
|
||||
_program.set_value ((*j)->program_number() + 1);
|
||||
_ignore_signals = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -327,17 +347,3 @@ PatchChangeDialog::bank_changed ()
|
|||
set_active_patch_combo ();
|
||||
}
|
||||
|
||||
MIDI::Name::ChannelNameSet::PatchBanks const *
|
||||
PatchChangeDialog::get_banks ()
|
||||
{
|
||||
MIDI::Name::MidiPatchManager& mpm = MIDI::Name::MidiPatchManager::instance ();
|
||||
boost::shared_ptr<MIDI::Name::ChannelNameSet> channel_name_set = mpm.find_channel_name_set (
|
||||
_model_name, _custom_device_mode, _channel.get_value_as_int() - 1
|
||||
);
|
||||
|
||||
if (!channel_name_set) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return &channel_name_set->patch_banks ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
namespace ARDOUR {
|
||||
class BeatsFramesConverter;
|
||||
class Session;
|
||||
class InstrumentInfo;
|
||||
}
|
||||
|
||||
namespace MIDI {
|
||||
|
|
@ -43,8 +44,7 @@ public:
|
|||
const ARDOUR::BeatsFramesConverter *,
|
||||
ARDOUR::Session *,
|
||||
Evoral::PatchChange<Evoral::MusicalTime> const &,
|
||||
std::string const &,
|
||||
std::string const &,
|
||||
ARDOUR::InstrumentInfo&,
|
||||
const Gtk::BuiltinStockID &
|
||||
);
|
||||
|
||||
|
|
@ -61,11 +61,8 @@ private:
|
|||
void bank_changed ();
|
||||
void program_changed ();
|
||||
|
||||
MIDI::Name::ChannelNameSet::PatchBanks const * get_banks ();
|
||||
|
||||
const ARDOUR::BeatsFramesConverter* _time_converter;
|
||||
std::string _model_name;
|
||||
std::string _custom_device_mode;
|
||||
ARDOUR::InstrumentInfo& _info;
|
||||
AudioClock _time;
|
||||
Gtk::SpinButton _channel;
|
||||
Gtk::SpinButton _program;
|
||||
|
|
@ -75,4 +72,7 @@ private:
|
|||
|
||||
boost::shared_ptr<MIDI::Name::PatchBank> _current_patch_bank;
|
||||
bool _ignore_signals;
|
||||
|
||||
void instrument_info_changed ();
|
||||
PBD::ScopedConnection _info_changed_connection;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@
|
|||
#include "ardour/audioengine.h"
|
||||
#include "ardour/internal_return.h"
|
||||
#include "ardour/internal_send.h"
|
||||
#include "ardour/midi_track.h"
|
||||
#include "ardour/plugin_insert.h"
|
||||
#include "ardour/port_insert.h"
|
||||
#include "ardour/profile.h"
|
||||
|
|
@ -412,6 +411,7 @@ ProcessorEntry::Control::Control (Glib::RefPtr<Gdk::Pixbuf> s, Glib::RefPtr<Gdk:
|
|||
: _control (c)
|
||||
, _adjustment (gain_to_slider_position_with_max (1.0, Config->get_max_gain()), 0, 1, 0.01, 0.1)
|
||||
, _slider (s, sd, &_adjustment, 0, false)
|
||||
, _slider_persistant_tooltip (&_slider)
|
||||
, _button (ArdourButton::Element (ArdourButton::Text | ArdourButton::Indicator))
|
||||
, _ignore_ui_adjustment (false)
|
||||
, _visible (false)
|
||||
|
|
@ -451,8 +451,13 @@ ProcessorEntry::Control::Control (Glib::RefPtr<Gdk::Pixbuf> s, Glib::RefPtr<Gdk:
|
|||
c->Changed.connect (_connection, MISSING_INVALIDATOR, boost::bind (&Control::control_changed, this), gui_context ());
|
||||
}
|
||||
|
||||
ARDOUR_UI::RapidScreenUpdate.connect (sigc::mem_fun (*this, &Control::control_changed));
|
||||
|
||||
control_changed ();
|
||||
set_tooltip ();
|
||||
|
||||
/* We're providing our own PersistentTooltip */
|
||||
set_no_tooltip_whatsoever (_slider);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -469,11 +474,12 @@ ProcessorEntry::Control::set_tooltip ()
|
|||
if (c->toggled ()) {
|
||||
s << (c->get_value() > 0.5 ? _("on") : _("off"));
|
||||
} else {
|
||||
s << c->internal_to_interface (c->get_value ());
|
||||
s << setprecision(2) << fixed;
|
||||
s << c->internal_to_user (c->get_value ());
|
||||
}
|
||||
|
||||
ARDOUR_UI::instance()->set_tip (_label, s.str ());
|
||||
ARDOUR_UI::instance()->set_tip (_slider, s.str ());
|
||||
_slider_persistant_tooltip.set_tip (s.str ());
|
||||
ARDOUR_UI::instance()->set_tip (_button, s.str ());
|
||||
}
|
||||
|
||||
|
|
@ -497,6 +503,7 @@ ProcessorEntry::Control::slider_adjusted ()
|
|||
}
|
||||
|
||||
c->set_value (c->interface_to_internal (_adjustment.get_value ()));
|
||||
set_tooltip ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -536,8 +543,6 @@ ProcessorEntry::Control::control_changed ()
|
|||
s.precision (1);
|
||||
s.setf (ios::fixed, ios::floatfield);
|
||||
s << c->internal_to_user (c->get_value ());
|
||||
|
||||
_slider.set_tooltip_text (s.str ());
|
||||
}
|
||||
|
||||
_ignore_ui_adjustment = false;
|
||||
|
|
@ -859,10 +864,8 @@ ProcessorBox::build_possible_aux_menu ()
|
|||
{
|
||||
boost::shared_ptr<RouteList> rl = _session->get_routes_with_internal_returns();
|
||||
|
||||
if (rl->empty() || boost::dynamic_pointer_cast<MidiTrack> (_route)) {
|
||||
/* No aux sends if there are no busses, or if this route is a MIDI track
|
||||
(one day, but not now ...)
|
||||
*/
|
||||
if (rl->empty()) {
|
||||
/* No aux sends if there are no busses */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "gtkmm2ext/click_box.h"
|
||||
#include "gtkmm2ext/dndvbox.h"
|
||||
#include "gtkmm2ext/pixfader.h"
|
||||
#include "gtkmm2ext/persistent_tooltip.h"
|
||||
|
||||
#include "pbd/stateful.h"
|
||||
#include "pbd/signals.h"
|
||||
|
|
@ -156,7 +157,7 @@ private:
|
|||
PBD::ScopedConnection active_connection;
|
||||
PBD::ScopedConnection name_connection;
|
||||
|
||||
class Control {
|
||||
class Control : public sigc::trackable {
|
||||
public:
|
||||
Control (Glib::RefPtr<Gdk::Pixbuf>, Glib::RefPtr<Gdk::Pixbuf>, boost::shared_ptr<ARDOUR::AutomationControl>, std::string const &);
|
||||
|
||||
|
|
@ -189,6 +190,7 @@ private:
|
|||
Gtk::Adjustment _adjustment;
|
||||
Gtkmm2ext::HSliderController _slider;
|
||||
Gtk::Label _label;
|
||||
Gtkmm2ext::PersistentTooltip _slider_persistant_tooltip;
|
||||
/* things for a button */
|
||||
ArdourButton _button;
|
||||
bool _ignore_ui_adjustment;
|
||||
|
|
|
|||
|
|
@ -274,6 +274,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible {
|
|||
virtual void remove_last_capture () = 0;
|
||||
virtual void maximise_editing_space () = 0;
|
||||
virtual void restore_editing_space () = 0;
|
||||
virtual void update_tearoff_visibility () = 0;
|
||||
virtual framepos_t get_preferred_edit_position (bool ignore_playhead = false, bool from_context_menu = false) = 0;
|
||||
virtual void toggle_meter_updating() = 0;
|
||||
virtual void split_region_at_points (boost::shared_ptr<ARDOUR::Region>, ARDOUR::AnalysisFeatureList&, bool can_ferret, bool select_new = false) = 0;
|
||||
|
|
|
|||
|
|
@ -779,7 +779,7 @@ RegionView::update_coverage_frames (LayerDisplay d)
|
|||
bool me = false;
|
||||
|
||||
/* the color that will be used to show parts of regions that will not be heard */
|
||||
uint32_t non_playing_color = RGBA_TO_UINT (32, 32, 32, 192);
|
||||
uint32_t const non_playing_color = ARDOUR_UI::config()->canvasvar_CoveredRegion.get ();
|
||||
|
||||
while (t < end) {
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, Canvas& c
|
|||
, mode_menu (0)
|
||||
, color_mode_menu (0)
|
||||
, gm (sess, slider, slider_desensitised, true, 115)
|
||||
, _ignore_set_layer_display (false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -185,6 +186,11 @@ RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
|
|||
}
|
||||
|
||||
rec_enable_button->set_sensitive (_session->writable());
|
||||
|
||||
/* set playlist button tip to the current playlist, and make it update when it changes */
|
||||
update_playlist_tip ();
|
||||
track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context());
|
||||
|
||||
}
|
||||
|
||||
controls_hbox.pack_start(gm.get_level_meter(), false, false);
|
||||
|
|
@ -204,7 +210,6 @@ RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
|
|||
ARDOUR_UI::instance()->set_tip(*solo_button,_("Solo"));
|
||||
ARDOUR_UI::instance()->set_tip(*mute_button,_("Mute"));
|
||||
ARDOUR_UI::instance()->set_tip(route_group_button, _("Route Group"));
|
||||
ARDOUR_UI::instance()->set_tip(playlist_button,_("Playlist"));
|
||||
|
||||
if (is_midi_track()) {
|
||||
ARDOUR_UI::instance()->set_tip(automation_button, _("MIDI Controllers and Automation"));
|
||||
|
|
@ -480,21 +485,21 @@ RouteTimeAxisView::build_display_menu ()
|
|||
select the active one, no toggled signal is emitted so nothing happens.
|
||||
*/
|
||||
|
||||
_ignore_set_layer_display = true;
|
||||
|
||||
layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid")));
|
||||
RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
|
||||
i->set_active (overlaid != 0 && stacked == 0);
|
||||
i->set_inconsistent (overlaid != 0 && stacked != 0);
|
||||
i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true));
|
||||
|
||||
layers_items.push_back (
|
||||
RadioMenuElem (layers_group, _("Stacked"),
|
||||
sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true))
|
||||
);
|
||||
|
||||
layers_items.push_back (RadioMenuElem (layers_group, _("Stacked")));
|
||||
i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
|
||||
i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
|
||||
i->set_active (overlaid == 0 && stacked != 0);
|
||||
i->set_inconsistent (overlaid != 0 && stacked != 0);
|
||||
i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
|
||||
|
||||
_ignore_set_layer_display = false;
|
||||
|
||||
items.push_back (MenuElem (_("Layers"), *layers_menu));
|
||||
|
||||
|
|
@ -1544,7 +1549,7 @@ RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist>
|
|||
boost::shared_ptr<RouteList> rl (rg->route_list());
|
||||
|
||||
for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
|
||||
if ( (*i) == this->route()) {
|
||||
if ((*i) == this->route()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1555,6 +1560,11 @@ RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist>
|
|||
continue;
|
||||
}
|
||||
|
||||
if (track->freeze_state() == Track::Frozen) {
|
||||
/* Don't change playlists of frozen tracks */
|
||||
continue;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
|
||||
if (!ipl) {
|
||||
// No playlist for this track for this take yet, make it
|
||||
|
|
@ -1567,6 +1577,35 @@ RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist>
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
RouteTimeAxisView::update_playlist_tip ()
|
||||
{
|
||||
RouteGroup* rg = route_group ();
|
||||
if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::edit.property_id)) {
|
||||
string group_string = "." + rg->name() + ".";
|
||||
|
||||
string take_name = track()->playlist()->name();
|
||||
string::size_type idx = take_name.find(group_string);
|
||||
|
||||
if (idx != string::npos) {
|
||||
/* find the bit containing the take number / name */
|
||||
take_name = take_name.substr (idx + group_string.length());
|
||||
|
||||
/* set the playlist button tooltip to the take name */
|
||||
ARDOUR_UI::instance()->set_tip (
|
||||
playlist_button,
|
||||
string_compose(_("Take: %1.%2"), escape_angled_brackets (rg->name()), escape_angled_brackets (take_name))
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* set the playlist button tooltip to the playlist name */
|
||||
ARDOUR_UI::instance()->set_tip (playlist_button, _("Playlist") + std::string(": ") + escape_angled_brackets (track()->playlist()->name()));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RouteTimeAxisView::show_playlist_selector ()
|
||||
{
|
||||
|
|
@ -2137,6 +2176,10 @@ RouteTimeAxisView::update_rec_display ()
|
|||
void
|
||||
RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
|
||||
{
|
||||
if (_ignore_set_layer_display) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (apply_to_selection) {
|
||||
_editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -306,11 +306,12 @@ protected:
|
|||
typedef std::list<RouteTimeAxisView*> UnderlayMirrorList;
|
||||
UnderlayMirrorList _underlay_mirrors;
|
||||
|
||||
bool _ignore_track_mode_change; ///< true to ignore track mode change signals
|
||||
bool _ignore_set_layer_display;
|
||||
|
||||
private:
|
||||
|
||||
void remove_child (boost::shared_ptr<TimeAxisView>);
|
||||
void update_playlist_tip ();
|
||||
};
|
||||
|
||||
#endif /* __ardour_route_time_axis_h__ */
|
||||
|
|
|
|||
|
|
@ -712,7 +712,7 @@ SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
|
|||
void
|
||||
SoundFileBrowser::update_preview ()
|
||||
{
|
||||
if (preview.setup_labels (chooser.get_filename())) {
|
||||
if (preview.setup_labels (chooser.get_preview_filename())) {
|
||||
if (preview.autoplay()) {
|
||||
Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1038,9 +1038,14 @@ ArdourStartup::setup_existing_session_page ()
|
|||
|
||||
existing_session_chooser.set_title (_("Select session file"));
|
||||
existing_session_chooser.signal_file_set().connect (sigc::mem_fun (*this, &ArdourStartup::existing_session_selected));
|
||||
cerr << "Set existing chooser to " << Config->get_default_session_parent_dir() << endl;
|
||||
existing_session_chooser.set_current_folder(poor_mans_glob (Config->get_default_session_parent_dir()));
|
||||
|
||||
FileFilter session_filter;
|
||||
session_filter.add_pattern ("*.ardour");
|
||||
session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
|
||||
existing_session_chooser.add_filter (session_filter);
|
||||
existing_session_chooser.set_filter (session_filter);
|
||||
|
||||
#ifdef GTKOSX
|
||||
existing_session_chooser.add_shortcut_folder ("/Volumes");
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "gtkmm2ext/gtk_ui.h"
|
||||
#include "gtkmm2ext/keyboard.h"
|
||||
#include "gtkmm2ext/utils.h"
|
||||
#include "gtkmm2ext/persistent_tooltip.h"
|
||||
|
||||
#include "ardour/pannable.h"
|
||||
#include "ardour/panner.h"
|
||||
|
|
@ -70,6 +71,7 @@ StereoPanner::StereoPanner (boost::shared_ptr<Panner> panner)
|
|||
, detented (false)
|
||||
, position_binder (position_control)
|
||||
, width_binder (width_control)
|
||||
, _dragging (false)
|
||||
{
|
||||
if (!have_colors) {
|
||||
set_colors ();
|
||||
|
|
@ -80,6 +82,8 @@ StereoPanner::StereoPanner (boost::shared_ptr<Panner> panner)
|
|||
width_control->Changed.connect (connections, invalidator(*this), boost::bind (&StereoPanner::value_change, this), gui_context());
|
||||
|
||||
ColorsChanged.connect (sigc::mem_fun (*this, &StereoPanner::color_handler));
|
||||
|
||||
set_tooltip ();
|
||||
}
|
||||
|
||||
StereoPanner::~StereoPanner ()
|
||||
|
|
@ -88,12 +92,8 @@ StereoPanner::~StereoPanner ()
|
|||
}
|
||||
|
||||
void
|
||||
StereoPanner::set_drag_data ()
|
||||
StereoPanner::set_tooltip ()
|
||||
{
|
||||
if (!_drag_data_label) {
|
||||
return;
|
||||
}
|
||||
|
||||
double pos = position_control->get_value(); // 0..1
|
||||
|
||||
/* We show the position of the center of the image relative to the left & right.
|
||||
|
|
@ -108,7 +108,7 @@ StereoPanner::set_drag_data ()
|
|||
snprintf (buf, sizeof (buf), "L:%3d R:%3d Width:%d%%", (int) rint (100.0 * (1.0 - pos)),
|
||||
(int) rint (100.0 * pos),
|
||||
(int) floor (100.0 * width_control->get_value()));
|
||||
_drag_data_label->set_markup (buf);
|
||||
_tooltip.set_tip (buf);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -360,8 +360,6 @@ StereoPanner::on_button_press_event (GdkEventButton* ev)
|
|||
return true;
|
||||
}
|
||||
|
||||
show_drag_data_window ();
|
||||
|
||||
if (ev->y < 20) {
|
||||
/* top section of widget is for position drags */
|
||||
dragging_position = true;
|
||||
|
|
@ -395,6 +393,7 @@ StereoPanner::on_button_press_event (GdkEventButton* ev)
|
|||
}
|
||||
|
||||
_dragging = true;
|
||||
_tooltip.target_start_drag ();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -414,14 +413,13 @@ StereoPanner::on_button_release_event (GdkEventButton* ev)
|
|||
bool const dp = dragging_position;
|
||||
|
||||
_dragging = false;
|
||||
_tooltip.target_stop_drag ();
|
||||
dragging_position = false;
|
||||
dragging_left = false;
|
||||
dragging_right = false;
|
||||
accumulated_delta = 0;
|
||||
detented = false;
|
||||
|
||||
hide_drag_data_window ();
|
||||
|
||||
if (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier)) {
|
||||
_panner->reset ();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class StereoPanner : public PannerInterface
|
|||
BindingProxy position_binder;
|
||||
BindingProxy width_binder;
|
||||
|
||||
void set_drag_data ();
|
||||
void set_tooltip ();
|
||||
|
||||
struct ColorScheme {
|
||||
uint32_t outline;
|
||||
|
|
@ -88,6 +88,8 @@ class StereoPanner : public PannerInterface
|
|||
Inverted
|
||||
};
|
||||
|
||||
bool _dragging;
|
||||
|
||||
static ColorScheme colors[3];
|
||||
static void set_colors ();
|
||||
static bool have_colors;
|
||||
|
|
|
|||
|
|
@ -613,6 +613,8 @@ StreamView::update_contents_height ()
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ContentsHeightChanged (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ public:
|
|||
|
||||
sigc::signal<void, RegionView*> RegionViewAdded;
|
||||
sigc::signal<void> RegionViewRemoved;
|
||||
/** Emitted when the height of regions has changed */
|
||||
sigc::signal<void> ContentsHeightChanged;
|
||||
|
||||
protected:
|
||||
StreamView (RouteTimeAxisView&, ArdourCanvas::Group* background_group = 0, ArdourCanvas::Group* canvas_group = 0);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/paned.h>
|
||||
#include <gtk/gtkpaned.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "pbd/file_utils.h"
|
||||
|
||||
|
|
@ -680,6 +681,16 @@ escape_underscores (string const & s)
|
|||
return o;
|
||||
}
|
||||
|
||||
/** Replace < and > with < and > respectively to make < > display correctly in markup strings */
|
||||
string
|
||||
escape_angled_brackets (string const & s)
|
||||
{
|
||||
string o = s;
|
||||
boost::replace_all (o, "<", "<");
|
||||
boost::replace_all (o, ">", ">");
|
||||
return o;
|
||||
}
|
||||
|
||||
Gdk::Color
|
||||
unique_random_color (list<Gdk::Color>& used_colors)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ void set_pango_fontsize ();
|
|||
void resize_window_to_proportion_of_monitor (Gtk::Window*, int, int);
|
||||
|
||||
std::string escape_underscores (std::string const &);
|
||||
std::string escape_angled_brackets (std::string const &);
|
||||
|
||||
Gdk::Color unique_random_color (std::list<Gdk::Color> &);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ Amp::Amp (Session& s)
|
|||
, _apply_gain(true)
|
||||
, _apply_gain_automation(false)
|
||||
, _current_gain(1.0)
|
||||
, _gain_automation_buffer(0)
|
||||
{
|
||||
Evoral::Parameter p (GainAutomation);
|
||||
/* gain range of -inf to +6dB, default 0dB */
|
||||
|
|
@ -84,7 +85,8 @@ Amp::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/,
|
|||
|
||||
if (_apply_gain_automation) {
|
||||
|
||||
gain_t* gab = _session.gain_automation_buffer ();
|
||||
gain_t* gab = _gain_automation_buffer;
|
||||
assert (gab);
|
||||
|
||||
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
|
||||
Sample* const sp = i->data();
|
||||
|
|
@ -440,14 +442,19 @@ Amp::GainControl::internal_to_user (double v) const
|
|||
return accurate_coefficient_to_dB (v);
|
||||
}
|
||||
|
||||
/** Write gain automation for this cycle into the buffer previously passed in to
|
||||
* set_gain_automation_buffer (if we are in automation playback mode and the
|
||||
* transport is rolling).
|
||||
*/
|
||||
void
|
||||
Amp::setup_gain_automation (framepos_t start_frame, framepos_t end_frame, framecnt_t nframes)
|
||||
{
|
||||
Glib::Mutex::Lock am (control_lock(), Glib::TRY_LOCK);
|
||||
|
||||
if (am.locked() && _session.transport_rolling() && _gain_control->automation_playback()) {
|
||||
assert (_gain_automation_buffer);
|
||||
_apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector (
|
||||
start_frame, end_frame, _session.gain_automation_buffer(), nframes);
|
||||
start_frame, end_frame, _gain_automation_buffer, nframes);
|
||||
} else {
|
||||
_apply_gain_automation = false;
|
||||
}
|
||||
|
|
@ -471,3 +478,13 @@ Amp::value_as_string (boost::shared_ptr<AutomationControl> ac) const
|
|||
return Automatable::value_as_string (ac);
|
||||
}
|
||||
|
||||
/** Sets up the buffer that setup_gain_automation and ::run will use for
|
||||
* gain automationc curves. Must be called before setup_gain_automation,
|
||||
* and must be called with process lock held.
|
||||
*/
|
||||
|
||||
void
|
||||
Amp::set_gain_automation_buffer (gain_t* g)
|
||||
{
|
||||
_gain_automation_buffer = g;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ public:
|
|||
bool apply_gain () const { return _apply_gain; }
|
||||
void apply_gain (bool yn) { _apply_gain = yn; }
|
||||
|
||||
void set_gain_automation_buffer (gain_t *);
|
||||
|
||||
void setup_gain_automation (framepos_t start_frame, framepos_t end_frame, framecnt_t nframes);
|
||||
|
||||
bool apply_gain_automation() const { return _apply_gain_automation; }
|
||||
|
|
@ -107,6 +109,9 @@ private:
|
|||
float _current_gain;
|
||||
|
||||
boost::shared_ptr<GainControl> _gain_control;
|
||||
|
||||
/** Buffer that we should use for gain automation */
|
||||
gain_t* _gain_automation_buffer;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
#include "ardour/region.h"
|
||||
|
||||
class XMLNode;
|
||||
class AudioRegionTest;
|
||||
class AudioRegionReadTest;
|
||||
class PlaylistReadTest;
|
||||
|
||||
namespace ARDOUR {
|
||||
|
|
@ -194,7 +194,7 @@ class AudioRegion : public Region
|
|||
AudioRegion (SourceList &);
|
||||
|
||||
private:
|
||||
friend class ::AudioRegionTest;
|
||||
friend class ::AudioRegionReadTest;
|
||||
friend class ::PlaylistReadTest;
|
||||
|
||||
PBD::Property<bool> _envelope_active;
|
||||
|
|
|
|||
|
|
@ -86,17 +86,6 @@ class ExportHandler : public ExportElementFactory
|
|||
BroadcastInfoPtr broadcast_info;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/* Stuff for export configs
|
||||
* The multimap maps timespans to file specifications
|
||||
*/
|
||||
|
||||
typedef std::pair<ExportTimespanPtr, FileSpec> ConfigPair;
|
||||
typedef std::multimap<ExportTimespanPtr, FileSpec> ConfigMap;
|
||||
|
||||
typedef boost::shared_ptr<ExportGraphBuilder> GraphBuilderPtr;
|
||||
|
||||
private:
|
||||
/* Session::get_export_handler() should be used to obtain an export handler
|
||||
* This ensures that it doesn't go out of scope before finalize_audio_export is called
|
||||
|
|
@ -111,7 +100,7 @@ class ExportHandler : public ExportElementFactory
|
|||
bool add_export_config (ExportTimespanPtr timespan, ExportChannelConfigPtr channel_config,
|
||||
ExportFormatSpecPtr format, ExportFilenamePtr filename,
|
||||
BroadcastInfoPtr broadcast_info);
|
||||
void do_export (bool rt = false);
|
||||
void do_export ();
|
||||
|
||||
std::string get_cd_marker_filename(std::string filename, CDMarkerFormat format);
|
||||
|
||||
|
|
@ -120,11 +109,15 @@ class ExportHandler : public ExportElementFactory
|
|||
int process (framecnt_t frames);
|
||||
|
||||
Session & session;
|
||||
GraphBuilderPtr graph_builder;
|
||||
boost::shared_ptr<ExportGraphBuilder> graph_builder;
|
||||
ExportStatusPtr export_status;
|
||||
|
||||
/* The timespan and corresponding file specifications that we are exporting;
|
||||
there can be multiple FileSpecs for each ExportTimespan.
|
||||
*/
|
||||
typedef std::multimap<ExportTimespanPtr, FileSpec> ConfigMap;
|
||||
ConfigMap config_map;
|
||||
|
||||
bool realtime;
|
||||
bool normalizing;
|
||||
|
||||
/* Timespan management */
|
||||
|
|
|
|||
67
libs/ardour/ardour/instrument_info.h
Normal file
67
libs/ardour/ardour/instrument_info.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __ardour_instrument_info_h__
|
||||
#define __ardour_instrument_info_h__
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pbd/signals.h"
|
||||
|
||||
#include "midi++/midnam_patch.h"
|
||||
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Processor;
|
||||
|
||||
class 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>);
|
||||
|
||||
std::string get_patch_name (uint16_t bank, uint8_t program, uint8_t channel) const;
|
||||
std::string get_instrument_name () const;
|
||||
|
||||
boost::shared_ptr<MIDI::Name::ChannelNameSet> get_patches (uint8_t channel);
|
||||
|
||||
PBD::Signal0<void> Changed;
|
||||
|
||||
static const MIDI::Name::PatchBank::PatchNameList& general_midi_patches();
|
||||
|
||||
private:
|
||||
std::string external_instrument_model;
|
||||
std::string external_instrument_mode;
|
||||
|
||||
boost::weak_ptr<ARDOUR::Processor> internal_instrument;
|
||||
|
||||
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;
|
||||
|
||||
static MIDI::Name::PatchBank::PatchNameList _gm_patches;
|
||||
};
|
||||
|
||||
} /* namespace ARDOUR */
|
||||
|
||||
|
||||
#endif /* __ardour_instrument_info_h__ */
|
||||
|
|
@ -166,15 +166,16 @@ class Plugin : public PBD::StatefulDestructible, public Latent
|
|||
void monitoring_changed ();
|
||||
|
||||
struct PresetRecord {
|
||||
PresetRecord () : user (true) {}
|
||||
PresetRecord (const std::string& u, const std::string& l, bool s = true) : uri (u), label (l), user (s) {}
|
||||
PresetRecord () : number (-1), user (true) {}
|
||||
PresetRecord (const std::string& u, const std::string& l, int n = -1, bool s = true) : uri (u), label (l), number (n), user (s) {}
|
||||
|
||||
bool operator!= (PresetRecord const & a) const {
|
||||
return uri != a.uri || label != a.label;
|
||||
return number != a.number || uri != a.uri || label != a.label;
|
||||
}
|
||||
|
||||
std::string uri;
|
||||
std::string label;
|
||||
int number; // if <0, invalid
|
||||
bool user;
|
||||
};
|
||||
|
||||
|
|
@ -188,6 +189,26 @@ class Plugin : public PBD::StatefulDestructible, public Latent
|
|||
|
||||
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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public:
|
|||
static BufferSet& get_scratch_buffers (ChanCount count = ChanCount::ZERO);
|
||||
static BufferSet& get_mix_buffers (ChanCount count = ChanCount::ZERO);
|
||||
static gain_t* gain_automation_buffer ();
|
||||
static gain_t* send_gain_automation_buffer ();
|
||||
static pan_t** pan_automation_buffer ();
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "pbd/destructible.h"
|
||||
|
||||
#include "ardour/ardour.h"
|
||||
#include "ardour/instrument_info.h"
|
||||
#include "ardour/io.h"
|
||||
#include "ardour/types.h"
|
||||
#include "ardour/mute_master.h"
|
||||
|
|
@ -405,6 +406,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
|
|||
special case not covered by this utility function.
|
||||
*/
|
||||
boost::shared_ptr<Processor> the_instrument() const;
|
||||
InstrumentInfo& instrument_info() { return _instrument_info; }
|
||||
|
||||
void automation_snapshot (framepos_t now, bool force=false);
|
||||
void protect_automation ();
|
||||
|
|
@ -500,6 +502,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
|
|||
DataType _default_type;
|
||||
FedBy _fed_by;
|
||||
|
||||
InstrumentInfo _instrument_info;
|
||||
|
||||
virtual ChanCount input_streams () const;
|
||||
|
||||
protected:
|
||||
|
|
@ -599,6 +603,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
|
|||
boost::weak_ptr<Processor> _processor_after_last_custom_meter;
|
||||
/** true if the last custom meter position was at the end of the processor list */
|
||||
bool _last_custom_meter_was_at_end;
|
||||
|
||||
void reset_instrument_info ();
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
|||
|
|
@ -529,14 +529,14 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
|
||||
/* source management */
|
||||
|
||||
void import_audiofiles (ImportStatus&);
|
||||
void import_files (ImportStatus&);
|
||||
bool sample_rate_convert (ImportStatus&, std::string infile, std::string& outfile);
|
||||
std::string build_tmp_convert_name (std::string file);
|
||||
|
||||
boost::shared_ptr<ExportHandler> get_export_handler ();
|
||||
boost::shared_ptr<ExportStatus> get_export_status ();
|
||||
|
||||
int start_audio_export (framepos_t position, bool realtime);
|
||||
int start_audio_export (framepos_t position);
|
||||
|
||||
PBD::Signal1<int, framecnt_t> ProcessExport;
|
||||
static PBD::Signal2<void,std::string, std::string> Exported;
|
||||
|
|
@ -669,7 +669,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
|
||||
/* s/w "RAID" management */
|
||||
|
||||
framecnt_t available_capture_duration();
|
||||
boost::optional<framecnt_t> available_capture_duration();
|
||||
|
||||
/* I/O bundles */
|
||||
|
||||
|
|
@ -716,6 +716,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
return _current_trans_quarks;
|
||||
}
|
||||
|
||||
bool operation_in_progress (GQuark) const;
|
||||
|
||||
void add_commands (std::vector<Command*> const & cmds);
|
||||
|
||||
std::map<PBD::ID,PBD::StatefulDestructible*> registry;
|
||||
|
|
@ -743,6 +745,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
/* buffers for gain and pan */
|
||||
|
||||
gain_t* gain_automation_buffer () const;
|
||||
gain_t* send_gain_automation_buffer () const;
|
||||
pan_t** pan_automation_buffer () const;
|
||||
|
||||
void ensure_buffer_set (BufferSet& buffers, const ChanCount& howmany);
|
||||
|
|
@ -1328,16 +1331,21 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
/* S/W RAID */
|
||||
|
||||
struct space_and_path {
|
||||
uint32_t blocks; /* 4kB blocks */
|
||||
uint32_t blocks; ///< 4kB blocks
|
||||
bool blocks_unknown; ///< true if blocks is unknown
|
||||
std::string path;
|
||||
|
||||
space_and_path() {
|
||||
blocks = 0;
|
||||
}
|
||||
space_and_path ()
|
||||
: blocks (0)
|
||||
, blocks_unknown (true)
|
||||
{}
|
||||
};
|
||||
|
||||
struct space_and_path_ascending_cmp {
|
||||
bool operator() (space_and_path a, space_and_path b) {
|
||||
if (a.blocks_unknown != b.blocks_unknown) {
|
||||
return !a.blocks_unknown;
|
||||
}
|
||||
return a.blocks > b.blocks;
|
||||
}
|
||||
};
|
||||
|
|
@ -1347,6 +1355,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
|||
std::vector<space_and_path> session_dirs;
|
||||
std::vector<space_and_path>::iterator last_rr_session_dir;
|
||||
uint32_t _total_free_4k_blocks;
|
||||
/** If this is true, _total_free_4k_blocks is not definite,
|
||||
as one or more of the session directories' filesystems
|
||||
could not report free space.
|
||||
*/
|
||||
bool _total_free_4k_blocks_uncertain;
|
||||
Glib::Mutex space_lock;
|
||||
|
||||
bool no_questions_about_missing_files;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ public:
|
|||
BufferSet* scratch_buffers;
|
||||
BufferSet* mix_buffers;
|
||||
gain_t* gain_automation_buffer;
|
||||
gain_t* send_gain_automation_buffer;
|
||||
pan_t** pan_automation_buffer;
|
||||
uint32_t npan_buffers;
|
||||
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, fr
|
|||
|
||||
Evoral::RangeList<framepos_t> region_to_do = Evoral::subtract (region_range, done);
|
||||
|
||||
/* Read those bits, adding their bodies (the parts between end-of-fade-in
|
||||
/* Make a note to read those bits, adding their bodies (the parts between end-of-fade-in
|
||||
and start-of-fade-out) to the `done' list.
|
||||
*/
|
||||
|
||||
|
|
@ -335,7 +335,7 @@ AudioPlaylist::check_crossfades (Evoral::Range<framepos_t> range)
|
|||
} else {
|
||||
switch (_session.config.get_xfade_model()) {
|
||||
case FullCrossfade:
|
||||
len = bottom->last_frame () - top->first_frame ();
|
||||
len = bottom->last_frame () - top->first_frame () + 1;
|
||||
top->set_fade_in_is_short (false);
|
||||
break;
|
||||
case ShortCrossfade:
|
||||
|
|
@ -395,7 +395,7 @@ AudioPlaylist::check_crossfades (Evoral::Range<framepos_t> range)
|
|||
} else {
|
||||
switch (_session.config.get_xfade_model()) {
|
||||
case FullCrossfade:
|
||||
len = top->last_frame () - bottom->first_frame ();
|
||||
len = top->last_frame () - bottom->first_frame () + 1;
|
||||
break;
|
||||
case ShortCrossfade:
|
||||
len = _session.config.get_short_xfade_seconds() * _session.frame_rate();
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ AudioRegionImporter::prepare_sources ()
|
|||
|
||||
// import files
|
||||
// TODO: threading & exception handling
|
||||
session.import_audiofiles (status);
|
||||
session.import_files (status);
|
||||
|
||||
// Add imported sources to handlers map
|
||||
std::vector<string>::iterator file_it = status.paths.begin();
|
||||
|
|
|
|||
|
|
@ -2107,7 +2107,7 @@ AUPlugin::find_presets ()
|
|||
for (FactoryPresetMap::iterator i = factory_preset_map.begin(); i != factory_preset_map.end(); ++i) {
|
||||
/* XXX: dubious */
|
||||
string const uri = string_compose ("%1", _presets.size ());
|
||||
_presets.insert (make_pair (uri, Plugin::PresetRecord (uri, i->first)));
|
||||
_presets.insert (make_pair (uri, Plugin::PresetRecord (uri, i->first, i->second)));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -623,7 +623,6 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
|
|||
if (opaque()) {
|
||||
if (_inverse_fade_in) {
|
||||
|
||||
|
||||
/* explicit inverse fade in curve (e.g. for constant
|
||||
* power), so we have to fetch it.
|
||||
*/
|
||||
|
|
@ -655,7 +654,6 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
|
|||
_fade_in->curve().get_vector (internal_offset, internal_offset + fade_in_limit, gain_buffer, fade_in_limit);
|
||||
}
|
||||
|
||||
|
||||
/* Mix our newly-read data in, with the fade */
|
||||
for (framecnt_t n = 0; n < fade_in_limit; ++n) {
|
||||
buf[n] += mixdown_buffer[n] * gain_buffer[n];
|
||||
|
|
@ -1831,7 +1829,7 @@ AudioRegion::find_silence (Sample threshold, framecnt_t min_length, InterThreadI
|
|||
Evoral::Range<framepos_t>
|
||||
AudioRegion::body_range () const
|
||||
{
|
||||
return Evoral::Range<framepos_t> (first_frame() + _fade_in->back()->when, last_frame() - _fade_out->back()->when);
|
||||
return Evoral::Range<framepos_t> (first_frame() + _fade_in->back()->when + 1, last_frame() - _fade_out->back()->when);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@ ExportHandler::ExportHandler (Session & session)
|
|||
, session (session)
|
||||
, graph_builder (new ExportGraphBuilder (session))
|
||||
, export_status (session.get_export_status ())
|
||||
, realtime (false)
|
||||
, normalizing (false)
|
||||
, cue_tracknum (0)
|
||||
, cue_indexnum (0)
|
||||
|
|
@ -112,23 +111,23 @@ ExportHandler::ExportHandler (Session & session)
|
|||
|
||||
ExportHandler::~ExportHandler ()
|
||||
{
|
||||
// TODO remove files that were written but not finsihed
|
||||
// TODO remove files that were written but not finished
|
||||
}
|
||||
|
||||
/** Add an export to the `to-do' list */
|
||||
bool
|
||||
ExportHandler::add_export_config (ExportTimespanPtr timespan, ExportChannelConfigPtr channel_config,
|
||||
ExportFormatSpecPtr format, ExportFilenamePtr filename,
|
||||
BroadcastInfoPtr broadcast_info)
|
||||
{
|
||||
FileSpec spec (channel_config, format, filename, broadcast_info);
|
||||
ConfigPair pair (timespan, spec);
|
||||
config_map.insert (pair);
|
||||
config_map.insert (make_pair (timespan, spec));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ExportHandler::do_export (bool rt)
|
||||
ExportHandler::do_export ()
|
||||
{
|
||||
/* Count timespans */
|
||||
|
||||
|
|
@ -144,7 +143,6 @@ ExportHandler::do_export (bool rt)
|
|||
|
||||
/* Start export */
|
||||
|
||||
realtime = rt;
|
||||
start_timespan ();
|
||||
}
|
||||
|
||||
|
|
@ -159,13 +157,18 @@ ExportHandler::start_timespan ()
|
|||
return;
|
||||
}
|
||||
|
||||
/* finish_timespan pops the config_map entry that has been done, so
|
||||
this is the timespan to do this time
|
||||
*/
|
||||
current_timespan = config_map.begin()->first;
|
||||
|
||||
export_status->total_frames_current_timespan = current_timespan->get_length();
|
||||
export_status->timespan_name = current_timespan->name();
|
||||
export_status->processed_frames_current_timespan = 0;
|
||||
|
||||
/* Register file configurations to graph builder */
|
||||
|
||||
/* Here's the config_map entries that use this timespan */
|
||||
timespan_bounds = config_map.equal_range (current_timespan);
|
||||
graph_builder->reset ();
|
||||
graph_builder->set_current_timespan (current_timespan);
|
||||
|
|
@ -181,7 +184,7 @@ ExportHandler::start_timespan ()
|
|||
normalizing = false;
|
||||
session.ProcessExport.connect_same_thread (process_connection, boost::bind (&ExportHandler::process, this, _1));
|
||||
process_position = current_timespan->get_start();
|
||||
session.start_audio_export (process_position, realtime);
|
||||
session.start_audio_export (process_position);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ ardour_config_search_path ()
|
|||
|
||||
search_path = sp;
|
||||
have_path = true;
|
||||
std::cerr << "CONFIG PATH: " << search_path.to_string() << std::endl;
|
||||
info << "CONFIG PATH: " << search_path.to_string() << endmsg;
|
||||
}
|
||||
|
||||
return search_path;
|
||||
|
|
@ -153,7 +153,7 @@ ardour_data_search_path ()
|
|||
|
||||
search_path = sp;
|
||||
have_path = true;
|
||||
std::cerr << "DATA PATH: " << search_path.to_string() << std::endl;
|
||||
info << "DATA PATH: " << search_path.to_string() << endmsg;
|
||||
}
|
||||
|
||||
return search_path;
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ remove_file_source (boost::shared_ptr<Source> source)
|
|||
// is disabled at the GUI until the Source implementations are able to provide
|
||||
// the necessary API.
|
||||
void
|
||||
Session::import_audiofiles (ImportStatus& status)
|
||||
Session::import_files (ImportStatus& status)
|
||||
{
|
||||
typedef vector<boost::shared_ptr<Source> > Sources;
|
||||
Sources all_new_sources;
|
||||
|
|
|
|||
201
libs/ardour/instrument_info.cc
Normal file
201
libs/ardour/instrument_info.cc
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "pbd/compose.h"
|
||||
|
||||
#include "midi++/midnam_patch.h"
|
||||
|
||||
#include "ardour/instrument_info.h"
|
||||
#include "ardour/midi_patch_manager.h"
|
||||
#include "ardour/processor.h"
|
||||
#include "ardour/plugin.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace MIDI::Name;
|
||||
using std::string;
|
||||
|
||||
MIDI::Name::PatchBank::PatchNameList InstrumentInfo::_gm_patches;
|
||||
|
||||
InstrumentInfo::InstrumentInfo ()
|
||||
: external_instrument_model (_("Unknown"))
|
||||
{
|
||||
}
|
||||
|
||||
InstrumentInfo::~InstrumentInfo ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
InstrumentInfo::set_external_instrument (const string& model, const string& mode)
|
||||
{
|
||||
external_instrument_model = model;
|
||||
external_instrument_mode = mode;
|
||||
internal_instrument.reset ();
|
||||
Changed(); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
void
|
||||
InstrumentInfo::set_internal_instrument (boost::shared_ptr<Processor> p)
|
||||
{
|
||||
internal_instrument = p;
|
||||
external_instrument_model = (_("Unknown"));
|
||||
external_instrument_mode = "";
|
||||
Changed(); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
string
|
||||
InstrumentInfo::get_instrument_name () 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);
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
InstrumentInfo::get_patch_name (uint16_t bank, uint8_t program, uint8_t channel) const
|
||||
{
|
||||
boost::shared_ptr<Processor> p = internal_instrument.lock();
|
||||
|
||||
if (p) {
|
||||
return get_plugin_patch_name (p, bank, program, channel);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (patch) {
|
||||
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)
|
||||
|
||||
return string_compose ("prg %1 bnk %2",program + MIDI_BP_ZERO , bank + MIDI_BP_ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
boost::shared_ptr<MIDI::Name::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);
|
||||
}
|
||||
|
||||
return MidiPatchManager::instance().find_channel_name_set (external_instrument_model,
|
||||
external_instrument_mode,
|
||||
channel);
|
||||
|
||||
}
|
||||
|
||||
boost::shared_ptr<MIDI::Name::ChannelNameSet>
|
||||
InstrumentInfo::plugin_programs_to_channel_name_set (boost::shared_ptr<Processor> p)
|
||||
{
|
||||
PatchBank::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;
|
||||
|
||||
/* XXX note the assumption that plugin presets start their numbering at
|
||||
* zero
|
||||
*/
|
||||
|
||||
for (n = 0, i = presets.begin(); i != presets.end(); ++i, ++n) {
|
||||
if ((*i).number >= 0) {
|
||||
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::PatchBank::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_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);
|
||||
}
|
||||
|
|
@ -176,10 +176,8 @@ InternalSend::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame
|
|||
Amp::apply_simple_gain (mixbufs, nframes, tgain);
|
||||
}
|
||||
|
||||
// Can't automate gain for sends or returns yet because we need different buffers
|
||||
// so that we don't overwrite the main automation data for the route amp
|
||||
// _amp->setup_gain_automation (start_frame, end_frame, nframes);
|
||||
|
||||
_amp->set_gain_automation_buffer (_session.send_gain_automation_buffer ());
|
||||
_amp->setup_gain_automation (start_frame, end_frame, nframes);
|
||||
_amp->run (mixbufs, start_frame, end_frame, nframes, true);
|
||||
|
||||
/* consider metering */
|
||||
|
|
|
|||
|
|
@ -1554,7 +1554,7 @@ LV2PluginInfo::discover()
|
|||
PluginInfoList* plugs = new PluginInfoList;
|
||||
const LilvPlugins* plugins = lilv_world_get_all_plugins(_world.world);
|
||||
|
||||
cerr << "LV2: Discovering " << lilv_plugins_size(plugins) << " plugins" << endl;
|
||||
info << "LV2: Discovering " << lilv_plugins_size(plugins) << " plugins" << endmsg;
|
||||
|
||||
LILV_FOREACH(plugins, i, plugins) {
|
||||
const LilvPlugin* p = lilv_plugins_get(plugins, i);
|
||||
|
|
@ -1605,7 +1605,5 @@ LV2PluginInfo::discover()
|
|||
plugs->push_back(info);
|
||||
}
|
||||
|
||||
cerr << "Done LV2 discovery" << endl;
|
||||
|
||||
return plugs;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <glibmm/thread.h>
|
||||
|
||||
#include "pbd/xml++.h"
|
||||
#include "pbd/filesystem.h"
|
||||
|
||||
#include "ardour/automation_control.h"
|
||||
#include "ardour/midi_model.h"
|
||||
|
|
@ -134,7 +135,7 @@ MidiRegion::clone (string path) const
|
|||
|
||||
PropertyList plist;
|
||||
|
||||
plist.add (Properties::name, ms->name());
|
||||
plist.add (Properties::name, sys::basename (ms->name()));
|
||||
plist.add (Properties::whole_file, true);
|
||||
plist.add (Properties::start, _start);
|
||||
plist.add (Properties::start_beats, _start_beats);
|
||||
|
|
|
|||
|
|
@ -2837,6 +2837,7 @@ Playlist::combine (const RegionList& r)
|
|||
/* make position relative to zero */
|
||||
|
||||
pl->add_region (copied_region, original_region->position() - earliest_position);
|
||||
copied_region->set_layer (original_region->layer ());
|
||||
|
||||
/* use the maximum number of channels for any region */
|
||||
|
||||
|
|
|
|||
|
|
@ -134,6 +134,17 @@ ProcessThread::gain_automation_buffer()
|
|||
return g;
|
||||
}
|
||||
|
||||
gain_t*
|
||||
ProcessThread::send_gain_automation_buffer()
|
||||
{
|
||||
ThreadBuffers* tb = _private_thread_buffers->get();
|
||||
assert (tb);
|
||||
|
||||
gain_t* g = tb->send_gain_automation_buffer;
|
||||
assert (g);
|
||||
return g;
|
||||
}
|
||||
|
||||
pan_t**
|
||||
ProcessThread::pan_automation_buffer()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -423,6 +423,7 @@ Route::process_output_buffers (BufferSet& bufs,
|
|||
|
||||
/* figure out if we're going to use gain automation */
|
||||
if (gain_automation_ok) {
|
||||
_amp->set_gain_automation_buffer (_session.gain_automation_buffer ());
|
||||
_amp->setup_gain_automation (start_frame, end_frame, nframes);
|
||||
} else {
|
||||
_amp->apply_gain_automation (false);
|
||||
|
|
@ -1013,6 +1014,7 @@ Route::add_processor (boost::shared_ptr<Processor> processor, boost::shared_ptr<
|
|||
_output->set_user_latency (0);
|
||||
}
|
||||
|
||||
reset_instrument_info ();
|
||||
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
|
||||
set_processor_positions ();
|
||||
|
||||
|
|
@ -1161,6 +1163,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
|
|||
_output->set_user_latency (0);
|
||||
}
|
||||
|
||||
reset_instrument_info ();
|
||||
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
|
||||
set_processor_positions ();
|
||||
|
||||
|
|
@ -1367,6 +1370,8 @@ Route::clear_processors (Placement p)
|
|||
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
|
||||
set_processor_positions ();
|
||||
|
||||
reset_instrument_info ();
|
||||
|
||||
if (!already_deleting) {
|
||||
_session.clear_deletion_in_progress();
|
||||
}
|
||||
|
|
@ -1465,6 +1470,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
|
|||
}
|
||||
}
|
||||
|
||||
reset_instrument_info ();
|
||||
processor->drop_references ();
|
||||
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
|
||||
set_processor_positions ();
|
||||
|
|
@ -1561,12 +1567,20 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
|
|||
(*i)->drop_references ();
|
||||
}
|
||||
|
||||
reset_instrument_info ();
|
||||
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
|
||||
set_processor_positions ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Route::reset_instrument_info ()
|
||||
{
|
||||
boost::shared_ptr<Processor> instr = the_instrument();
|
||||
_instrument_info.set_internal_instrument (instr);
|
||||
}
|
||||
|
||||
/** Caller must hold process lock */
|
||||
int
|
||||
Route::configure_processors (ProcessorStreams* err)
|
||||
|
|
@ -2525,6 +2539,7 @@ Route::set_processor_state (const XMLNode& node)
|
|||
}
|
||||
}
|
||||
|
||||
reset_instrument_info ();
|
||||
processors_changed (RouteProcessorChange ());
|
||||
set_processor_positions ();
|
||||
}
|
||||
|
|
@ -4049,10 +4064,12 @@ Route::the_instrument () const
|
|||
{
|
||||
Glib::RWLock::WriterLock lm (_processor_lock);
|
||||
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
if (boost::dynamic_pointer_cast<PluginInsert>(*i)) {
|
||||
if ((*i)->input_streams().n_midi() > 0 &&
|
||||
(*i)->output_streams().n_audio() > 0) {
|
||||
return (*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return boost::shared_ptr<Processor>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,9 +137,8 @@ Send::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframe
|
|||
|
||||
/* gain control */
|
||||
|
||||
// Can't automate gain for sends or returns yet because we need different buffers
|
||||
// so that we don't overwrite the main automation data for the route amp
|
||||
// _amp->setup_gain_automation (start_frame, end_frame, nframes);
|
||||
_amp->set_gain_automation_buffer (_session.send_gain_automation_buffer ());
|
||||
_amp->setup_gain_automation (start_frame, end_frame, nframes);
|
||||
_amp->run (sendbufs, start_frame, end_frame, nframes, true);
|
||||
|
||||
/* deliver to outputs */
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ Session::Session (AudioEngine &eng,
|
|||
, _all_route_group (new RouteGroup (*this, "all"))
|
||||
, routes (new RouteList)
|
||||
, _total_free_4k_blocks (0)
|
||||
, _total_free_4k_blocks_uncertain (false)
|
||||
, _bundles (new BundleList)
|
||||
, _bundle_xml_node (0)
|
||||
, _current_trans (0)
|
||||
|
|
@ -3501,9 +3502,16 @@ Session::graph_reordered ()
|
|||
}
|
||||
}
|
||||
|
||||
framecnt_t
|
||||
/** @return Number of frames that there is disk space available to write,
|
||||
* if known.
|
||||
*/
|
||||
boost::optional<framecnt_t>
|
||||
Session::available_capture_duration ()
|
||||
{
|
||||
if (_total_free_4k_blocks_uncertain) {
|
||||
return boost::optional<framecnt_t> ();
|
||||
}
|
||||
|
||||
float sample_bytes_on_disk = 4.0; // keep gcc happy
|
||||
|
||||
switch (config.get_native_file_data_format()) {
|
||||
|
|
@ -4082,6 +4090,12 @@ Session::gain_automation_buffer() const
|
|||
return ProcessThread::gain_automation_buffer ();
|
||||
}
|
||||
|
||||
gain_t*
|
||||
Session::send_gain_automation_buffer() const
|
||||
{
|
||||
return ProcessThread::send_gain_automation_buffer ();
|
||||
}
|
||||
|
||||
pan_t**
|
||||
Session::pan_automation_buffer() const
|
||||
{
|
||||
|
|
@ -4744,3 +4758,9 @@ Session::next_control_id () const
|
|||
{
|
||||
return ntracks() + nbusses() + 1;
|
||||
}
|
||||
|
||||
bool
|
||||
Session::operation_in_progress (GQuark op) const
|
||||
{
|
||||
return (find (_current_trans_quarks.begin(), _current_trans_quarks.end(), op) != _current_trans_quarks.end());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ Session::pre_export ()
|
|||
|
||||
/** Called for each range that is being exported */
|
||||
int
|
||||
Session::start_audio_export (framepos_t position, bool /* realtime */)
|
||||
Session::start_audio_export (framepos_t position)
|
||||
{
|
||||
if (!_exporting) {
|
||||
pre_export ();
|
||||
|
|
|
|||
|
|
@ -46,6 +46,10 @@
|
|||
#include <sys/mount.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STATVFS_H
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <glibmm.h>
|
||||
|
|
@ -2079,23 +2083,48 @@ Session::save_template (string template_name)
|
|||
void
|
||||
Session::refresh_disk_space ()
|
||||
{
|
||||
#if HAVE_SYS_VFS_H
|
||||
struct statfs statfsbuf;
|
||||
vector<space_and_path>::iterator i;
|
||||
#if HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H
|
||||
|
||||
Glib::Mutex::Lock lm (space_lock);
|
||||
double scale;
|
||||
|
||||
/* get freespace on every FS that is part of the session path */
|
||||
|
||||
_total_free_4k_blocks = 0;
|
||||
_total_free_4k_blocks_uncertain = false;
|
||||
|
||||
for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
|
||||
statfs ((*i).path.c_str(), &statfsbuf);
|
||||
for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
|
||||
|
||||
scale = statfsbuf.f_bsize/4096.0;
|
||||
struct statfs statfsbuf;
|
||||
statfs (i->path.c_str(), &statfsbuf);
|
||||
|
||||
(*i).blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
|
||||
_total_free_4k_blocks += (*i).blocks;
|
||||
double const scale = statfsbuf.f_bsize / 4096.0;
|
||||
|
||||
/* See if this filesystem is read-only */
|
||||
struct statvfs statvfsbuf;
|
||||
statvfs (i->path.c_str(), &statvfsbuf);
|
||||
|
||||
/* f_bavail can be 0 if it is undefined for whatever
|
||||
filesystem we are looking at; Samba shares mounted
|
||||
via GVFS are an example of this.
|
||||
*/
|
||||
if (statfsbuf.f_bavail == 0) {
|
||||
/* block count unknown */
|
||||
i->blocks = 0;
|
||||
i->blocks_unknown = true;
|
||||
} else if (statvfsbuf.f_flag & ST_RDONLY) {
|
||||
/* read-only filesystem */
|
||||
i->blocks = 0;
|
||||
i->blocks_unknown = false;
|
||||
} else {
|
||||
/* read/write filesystem with known space */
|
||||
i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
|
||||
i->blocks_unknown = false;
|
||||
}
|
||||
|
||||
_total_free_4k_blocks += i->blocks;
|
||||
if (i->blocks_unknown) {
|
||||
_total_free_4k_blocks_uncertain = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
94
libs/ardour/test/audio_region_read_test.cc
Normal file
94
libs/ardour/test/audio_region_read_test.cc
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "ardour/playlist.h"
|
||||
#include "ardour/region.h"
|
||||
#include "ardour/audioregion.h"
|
||||
#include "audio_region_read_test.h"
|
||||
#include "test_globals.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (AudioRegionReadTest);
|
||||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
|
||||
/** Check some basic reads */
|
||||
void
|
||||
AudioRegionReadTest::readTest ()
|
||||
{
|
||||
int const N = 1024;
|
||||
|
||||
Sample buf[N];
|
||||
Sample mbuf[N];
|
||||
float gbuf[N];
|
||||
|
||||
int const P = 100;
|
||||
|
||||
/* Simple read: 256 frames from start of region, no fades */
|
||||
|
||||
_ar[0]->set_position (P);
|
||||
_ar[0]->set_length (1024);
|
||||
|
||||
_ar[0]->read_from_sources (_ar[0]->_sources, _ar[0]->_length, buf, P, 256, 0);
|
||||
check_staircase (buf, 0, 256);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
buf[i] = 0;
|
||||
}
|
||||
|
||||
/* Offset read: 256 frames from 128 frames into the region, no fades */
|
||||
_ar[0]->read_from_sources (_ar[0]->_sources, _ar[0]->_length, buf, P + 128, 256, 0);
|
||||
check_staircase (buf, 128, 256);
|
||||
|
||||
/* Simple read with a fade-in: 256 frames from start of region, with fades */
|
||||
_ar[0]->set_default_fade_in ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_in->back()->when);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
buf[i] = 0;
|
||||
}
|
||||
|
||||
_ar[0]->read_at (buf, mbuf, gbuf, P, 256, 0);
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
/* XXX: this isn't very accurate, but close enough for now; needs investigation */
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * i / 63.0), buf[i], 1e-4);
|
||||
}
|
||||
for (int i = 64; i < P; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL (i, int (buf[i]));
|
||||
}
|
||||
|
||||
/* Offset read: 256 frames from 128 frames into the region, with fades
|
||||
(though the fade should not affect it, as it is finished before the read starts)
|
||||
*/
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
buf[i] = 0;
|
||||
}
|
||||
|
||||
_ar[0]->read_at (buf, mbuf, gbuf, P + 128, 256, 0);
|
||||
check_staircase (buf, 128, 256);
|
||||
}
|
||||
|
||||
void
|
||||
AudioRegionReadTest::check_staircase (Sample* b, int offset, int N)
|
||||
{
|
||||
for (int i = 0; i < N; ++i) {
|
||||
int const j = i + offset;
|
||||
CPPUNIT_ASSERT_EQUAL (j, int (b[i]));
|
||||
}
|
||||
}
|
||||
33
libs/ardour/test/audio_region_read_test.h
Normal file
33
libs/ardour/test/audio_region_read_test.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "ardour/types.h"
|
||||
#include "audio_region_test.h"
|
||||
|
||||
class AudioRegionReadTest : public AudioRegionTest
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (AudioRegionReadTest);
|
||||
CPPUNIT_TEST (readTest);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void readTest ();
|
||||
|
||||
private:
|
||||
void check_staircase (ARDOUR::Sample *, int, int);
|
||||
};
|
||||
|
|
@ -1,76 +1,85 @@
|
|||
#include "ardour/playlist.h"
|
||||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "pbd/filesystem.h"
|
||||
#include "pbd/compose.h"
|
||||
#include "ardour/playlist_factory.h"
|
||||
#include "ardour/source_factory.h"
|
||||
#include "ardour/region.h"
|
||||
#include "ardour/region_factory.h"
|
||||
#include "ardour/sndfilesource.h"
|
||||
#include "ardour/audioregion.h"
|
||||
#include "ardour/audioplaylist.h"
|
||||
#include "audio_region_test.h"
|
||||
#include "test_globals.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (AudioRegionTest);
|
||||
|
||||
using namespace std;
|
||||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
|
||||
void
|
||||
AudioRegionTest::readTest ()
|
||||
AudioRegionTest::setUp ()
|
||||
{
|
||||
int const N = 1024;
|
||||
TestNeedingSession::setUp ();
|
||||
|
||||
Sample buf[N];
|
||||
Sample mbuf[N];
|
||||
float gbuf[N];
|
||||
/* This is important, otherwise createWritable will mark the source immutable (hence unwritable) */
|
||||
unlink ("libs/ardour/test/test.wav");
|
||||
string const test_wav_path = "libs/ardour/test/test.wav";
|
||||
_playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test");
|
||||
_audio_playlist = boost::dynamic_pointer_cast<AudioPlaylist> (_playlist);
|
||||
_source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, Fs);
|
||||
|
||||
int const P = 100;
|
||||
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (_region[0]);
|
||||
/* Write a staircase to the source */
|
||||
|
||||
/* Simple read: 256 frames from start of region, no fades */
|
||||
boost::shared_ptr<SndFileSource> s = boost::dynamic_pointer_cast<SndFileSource> (_source);
|
||||
assert (s);
|
||||
|
||||
ar->set_position (P);
|
||||
ar->set_length (1024);
|
||||
int const signal_length = 4096;
|
||||
|
||||
ar->read_from_sources (ar->_sources, ar->_length, buf, P, 256, 0);
|
||||
check_staircase (buf, 0, 256);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
buf[i] = 0;
|
||||
Sample staircase[signal_length];
|
||||
for (int i = 0; i < signal_length; ++i) {
|
||||
staircase[i] = i;
|
||||
}
|
||||
|
||||
/* Offset read: 256 frames from 128 frames into the region, no fades */
|
||||
ar->read_from_sources (ar->_sources, ar->_length, buf, P + 128, 256, 0);
|
||||
check_staircase (buf, 128, 256);
|
||||
s->write (staircase, signal_length);
|
||||
|
||||
/* Simple read with a fade-in: 256 frames from start of region, with fades */
|
||||
ar->set_default_fade_in ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar->_fade_in->back()->when);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
buf[i] = 0;
|
||||
PropertyList plist;
|
||||
plist.add (Properties::start, 0);
|
||||
plist.add (Properties::length, 100);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
_r[i] = RegionFactory::create (_source, plist);
|
||||
_ar[i] = boost::dynamic_pointer_cast<AudioRegion> (_r[i]);
|
||||
_ar[i]->set_name (string_compose ("ar%1", i));
|
||||
}
|
||||
|
||||
ar->read_at (buf, mbuf, gbuf, P, 256, 0);
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
/* XXX: this isn't very accurate, but close enough for now; needs investigation */
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * i / 63.0), buf[i], 1e-4);
|
||||
}
|
||||
for (int i = 64; i < P; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL (i, int (buf[i]));
|
||||
}
|
||||
|
||||
/* Offset read: 256 frames from 128 frames into the region, with fades
|
||||
(though the fade should not affect it, as it is finished before the read starts)
|
||||
*/
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
buf[i] = 0;
|
||||
}
|
||||
|
||||
ar->read_at (buf, mbuf, gbuf, P + 128, 256, 0);
|
||||
check_staircase (buf, 128, 256);
|
||||
}
|
||||
|
||||
void
|
||||
AudioRegionTest::check_staircase (Sample* b, int offset, int N)
|
||||
AudioRegionTest::tearDown ()
|
||||
{
|
||||
for (int i = 0; i < N; ++i) {
|
||||
int const j = i + offset;
|
||||
CPPUNIT_ASSERT_EQUAL (j, int (b[i]));
|
||||
_playlist.reset ();
|
||||
_audio_playlist.reset ();
|
||||
_source.reset ();
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
_r[i].reset ();
|
||||
_ar[i].reset ();
|
||||
}
|
||||
|
||||
TestNeedingSession::tearDown ();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,50 @@
|
|||
#include "ardour/types.h"
|
||||
#include "test_needing_playlist_and_regions.h"
|
||||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
class AudioRegionTest : public TestNeedingPlaylistAndRegions
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "test_needing_session.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class Playlist;
|
||||
class AudioPlaylist;
|
||||
class Source;
|
||||
class Region;
|
||||
class AudioRegion;
|
||||
}
|
||||
|
||||
/** A parent class for tests which offers some audio regions,
|
||||
* each with a staircase waveform within them.
|
||||
*/
|
||||
class AudioRegionTest : public TestNeedingSession
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (AudioRegionTest);
|
||||
CPPUNIT_TEST (readTest);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void readTest ();
|
||||
virtual void setUp ();
|
||||
virtual void tearDown ();
|
||||
|
||||
private:
|
||||
void check_staircase (ARDOUR::Sample *, int, int);
|
||||
protected:
|
||||
boost::shared_ptr<ARDOUR::Playlist> _playlist;
|
||||
/** AudioPlaylist downcast of _playlist */
|
||||
boost::shared_ptr<ARDOUR::AudioPlaylist> _audio_playlist;
|
||||
boost::shared_ptr<ARDOUR::Source> _source;
|
||||
/** 16 regions, of length 100, each referencing a source which is 4096
|
||||
* frames of a staircase waveform.
|
||||
*/
|
||||
boost::shared_ptr<ARDOUR::Region> _r[16];
|
||||
/** AudioRegion downcasts of _r[] */
|
||||
boost::shared_ptr<ARDOUR::AudioRegion> _ar[16];
|
||||
};
|
||||
|
|
|
|||
250
libs/ardour/test/combine_regions_test.cc
Normal file
250
libs/ardour/test/combine_regions_test.cc
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "combine_regions_test.h"
|
||||
#include "ardour/types.h"
|
||||
#include "ardour/audioplaylist.h"
|
||||
#include "ardour/region.h"
|
||||
#include "ardour/audioregion.h"
|
||||
#include "evoral/Curve.hpp"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (CombineRegionsTest);
|
||||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
|
||||
void
|
||||
CombineRegionsTest::check_crossfade1 ()
|
||||
{
|
||||
ARDOUR::Sample buf[512];
|
||||
ARDOUR::Sample mbuf[512];
|
||||
float gbuf[512];
|
||||
|
||||
/* Read from the playlist */
|
||||
_audio_playlist->read (buf, mbuf, gbuf, 0, 256 * 2 - 128, 0);
|
||||
|
||||
/* _r[0]'s fade in */
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
float const fade = i / (double) 63;
|
||||
float const r0 = i * fade;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (r0, buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* Some more of _r[0] */
|
||||
for (int i = 64; i < 128; ++i) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (i, buf[i], 1e-16);
|
||||
}
|
||||
|
||||
float fade_in[128];
|
||||
float fade_out[128];
|
||||
|
||||
_ar[1]->fade_in()->curve().get_vector (0, 128, fade_in, 128);
|
||||
_ar[1]->inverse_fade_in()->curve().get_vector (0, 128, fade_out, 128);
|
||||
|
||||
/* Crossfading _r[0] to _r[1] using _r[1]'s fade in and inverse fade in.
|
||||
_r[0] also has a standard region fade out to add to the fun.
|
||||
*/
|
||||
for (int i = 128; i < 256; ++i) {
|
||||
|
||||
float region_fade_out = 1;
|
||||
if (i >= 192) {
|
||||
/* Ardour fades out from 1 to VERY_SMALL_SIGNAL, which is 0.0000001,
|
||||
so this fade out expression is a little long-winded.
|
||||
*/
|
||||
region_fade_out = (((double) 1 - 0.0000001) / 63) * (255 - i) + 0.0000001;
|
||||
}
|
||||
|
||||
/* This computation of r0 cannot be compressed into one line, or there
|
||||
is a small floating point `error'
|
||||
*/
|
||||
float r0 = i * region_fade_out;
|
||||
r0 *= fade_out[i - 128];
|
||||
|
||||
float const r1 = (i - 128) * fade_in[i - 128];
|
||||
cout << setprecision(12);
|
||||
cout << "\t\ti=" << i << " fade_out=" << fade_out[i - 128] << " r1=" << r1 << " r0=" << r0 << "\n";
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (r0 + r1, buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* Rest of _r[1] */
|
||||
for (int i = 256; i < (384 - 64); ++i) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (i - 128, buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* And _r[1]'s fade out */
|
||||
for (int i = (384 - 64); i < 384; ++i) {
|
||||
float const fade_out = (((double) 1 - 0.0000001) / 63) * (383 - i) + 0.0000001;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL ((i - 128) * fade_out, buf[i], 1e-16);
|
||||
}
|
||||
}
|
||||
|
||||
/** Test combining two cross-faded regions, with the earlier region
|
||||
* on the lower layer.
|
||||
*/
|
||||
void
|
||||
CombineRegionsTest::crossfadeTest1 ()
|
||||
{
|
||||
/* Two regions, both 256 frames in length, overlapping by 128 frames in the middle */
|
||||
|
||||
_ar[0]->set_default_fade_in ();
|
||||
_ar[0]->set_default_fade_out ();
|
||||
_ar[1]->set_default_fade_out ();
|
||||
|
||||
_playlist->add_region (_r[0], 0);
|
||||
_r[0]->set_length (256);
|
||||
|
||||
_playlist->add_region (_r[1], 128);
|
||||
_r[1]->set_length (256);
|
||||
|
||||
/* Check layering */
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (0), _r[0]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (1), _r[1]->layer ());
|
||||
|
||||
/* Check that the right fades have been set up */
|
||||
CPPUNIT_ASSERT_EQUAL (false, _ar[0]->fade_in_is_xfade ());
|
||||
CPPUNIT_ASSERT_EQUAL (false, _ar[0]->fade_out_is_xfade ());
|
||||
CPPUNIT_ASSERT_EQUAL (true, _ar[1]->fade_in_is_xfade ());
|
||||
CPPUNIT_ASSERT_EQUAL (false, _ar[1]->fade_out_is_xfade ());
|
||||
|
||||
/* Check that the read comes back correctly */
|
||||
check_crossfade1 ();
|
||||
|
||||
/* Combine the two regions */
|
||||
|
||||
RegionList rl;
|
||||
rl.push_back (_r[0]);
|
||||
rl.push_back (_r[1]);
|
||||
_playlist->combine (rl);
|
||||
|
||||
/* ...so we just have the one region... */
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t) 1, _playlist->n_regions ());
|
||||
|
||||
/* And reading should give the same thing */
|
||||
check_crossfade1 ();
|
||||
}
|
||||
|
||||
void
|
||||
CombineRegionsTest::check_crossfade2 ()
|
||||
{
|
||||
ARDOUR::Sample buf[512];
|
||||
ARDOUR::Sample mbuf[512];
|
||||
float gbuf[512];
|
||||
|
||||
/* Read from the playlist */
|
||||
_audio_playlist->read (buf, mbuf, gbuf, 0, 256 * 2 - 128, 0);
|
||||
|
||||
/* _r[0]'s fade in */
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
float const fade = i / (double) 63;
|
||||
float const r0 = i * fade;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (r0, buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* Some more of _r[0] */
|
||||
for (int i = 64; i < 128; ++i) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (i, buf[i], 1e-16);
|
||||
}
|
||||
|
||||
float fade_in[128];
|
||||
float fade_out[128];
|
||||
|
||||
_ar[0]->inverse_fade_out()->curve().get_vector (0, 128, fade_in, 128);
|
||||
_ar[0]->fade_out()->curve().get_vector (0, 128, fade_out, 128);
|
||||
|
||||
/* Crossfading _r[0] to _r[1] using _r[0]'s fade out and inverse fade out.
|
||||
_r[1] also has a standard region fade in to add to the fun.
|
||||
*/
|
||||
for (int i = 128; i < 256; ++i) {
|
||||
|
||||
float region_fade_in = 1;
|
||||
if (i < (128 + 64)) {
|
||||
region_fade_in = (i - 128) / ((double) 63);
|
||||
}
|
||||
|
||||
float r0 = i * fade_out[i - 128];
|
||||
float r1 = (i - 128) * region_fade_in;
|
||||
r1 *= fade_in[i - 128];
|
||||
|
||||
cout << setprecision(12);
|
||||
cout << "\t\ti=" << i << " fade_out=" << fade_out[i - 128] << " r1=" << r1 << " r0=" << r0 << "\n";
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (r0 + r1, buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* Rest of _r[1] */
|
||||
for (int i = 256; i < (384 - 64); ++i) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (i - 128, buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* And _r[1]'s fade out */
|
||||
for (int i = (384 - 64); i < 384; ++i) {
|
||||
float const fade_out = (((double) 1 - 0.0000001) / 63) * (383 - i) + 0.0000001;
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL ((i - 128) * fade_out, buf[i], 1e-16);
|
||||
}
|
||||
}
|
||||
|
||||
/** As per crossfadeTest1, except that the earlier region is on the
|
||||
* higher layer.
|
||||
*/
|
||||
void
|
||||
CombineRegionsTest::crossfadeTest2 ()
|
||||
{
|
||||
cout << "\n\n\nCOMBINE\n";
|
||||
|
||||
/* Two regions, both 256 frames in length, overlapping by 128 frames in the middle */
|
||||
|
||||
_ar[0]->set_default_fade_in ();
|
||||
_ar[0]->set_default_fade_out ();
|
||||
_ar[1]->set_default_fade_out ();
|
||||
|
||||
_playlist->add_region (_r[0], 0);
|
||||
_r[0]->set_length (256);
|
||||
|
||||
_playlist->add_region (_r[1], 128);
|
||||
_r[1]->set_length (256);
|
||||
|
||||
_r[1]->lower_to_bottom ();
|
||||
|
||||
/* Check layering */
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (1), _r[0]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (0), _r[1]->layer ());
|
||||
|
||||
/* Check that the right fades have been set up */
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL (false, _ar[0]->fade_in_is_xfade ());
|
||||
CPPUNIT_ASSERT_EQUAL (true, _ar[0]->fade_out_is_xfade ());
|
||||
CPPUNIT_ASSERT_EQUAL (false, _ar[1]->fade_in_is_xfade ());
|
||||
CPPUNIT_ASSERT_EQUAL (false, _ar[1]->fade_out_is_xfade ());
|
||||
|
||||
/* Check that the read comes back correctly */
|
||||
cout << "\n\n\nFIRST READ\n";
|
||||
check_crossfade2 ();
|
||||
|
||||
/* Combine the two regions */
|
||||
|
||||
RegionList rl;
|
||||
rl.push_back (_r[0]);
|
||||
rl.push_back (_r[1]);
|
||||
_playlist->combine (rl);
|
||||
|
||||
/* ...so we just have the one region... */
|
||||
CPPUNIT_ASSERT_EQUAL ((uint32_t) 1, _playlist->n_regions ());
|
||||
|
||||
/* And reading should give the same thing */
|
||||
check_crossfade2 ();
|
||||
}
|
||||
|
||||
39
libs/ardour/test/combine_regions_test.h
Normal file
39
libs/ardour/test/combine_regions_test.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "audio_region_test.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class AutomationList;
|
||||
}
|
||||
|
||||
class CombineRegionsTest : public AudioRegionTest
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (CombineRegionsTest);
|
||||
CPPUNIT_TEST (crossfadeTest1);
|
||||
CPPUNIT_TEST (crossfadeTest2);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void crossfadeTest1 ();
|
||||
void crossfadeTest2 ();
|
||||
|
||||
private:
|
||||
void check_crossfade1 ();
|
||||
void check_crossfade2 ();
|
||||
};
|
||||
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "control_surfaces_test.h"
|
||||
#include "ardour/control_protocol_manager.h"
|
||||
#include "ardour/session.h"
|
||||
|
|
@ -8,7 +26,7 @@ using namespace std;
|
|||
using namespace ARDOUR;
|
||||
|
||||
/** Instantiate and then immediately tear down all our control surfaces.
|
||||
* This is to check that there are no crashes when doing this ...
|
||||
* This is to check that there are no crashes when doing this.
|
||||
*/
|
||||
void
|
||||
ControlSurfacesTest::instantiateAndTeardownTest ()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,24 @@
|
|||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "test_needing_session.h"
|
||||
|
||||
/** Tests for control surfaces */
|
||||
class ControlSurfacesTest : public TestNeedingSession
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (ControlSurfacesTest);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "ardour/playlist.h"
|
||||
#include "ardour/region.h"
|
||||
#include "playlist_layering_test.h"
|
||||
|
|
@ -10,18 +28,18 @@ using namespace ARDOUR;
|
|||
void
|
||||
PlaylistLayeringTest::basicsTest ()
|
||||
{
|
||||
_playlist->add_region (_region[0], 0);
|
||||
_playlist->add_region (_region[1], 10);
|
||||
_playlist->add_region (_region[2], 20);
|
||||
_playlist->add_region (_r[0], 0);
|
||||
_playlist->add_region (_r[1], 10);
|
||||
_playlist->add_region (_r[2], 20);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[0]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[1]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[2]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (0), _r[0]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (1), _r[1]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (2), _r[2]->layer ());
|
||||
|
||||
_region[0]->set_position (5);
|
||||
_r[0]->set_position (5);
|
||||
|
||||
/* region move should have no effect */
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[0]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[1]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[2]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (0), _r[0]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (1), _r[1]->layer ());
|
||||
CPPUNIT_ASSERT_EQUAL (layer_t (2), _r[2]->layer ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,24 @@
|
|||
#include "test_needing_playlist_and_regions.h"
|
||||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
class PlaylistLayeringTest : public TestNeedingPlaylistAndRegions
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "audio_region_test.h"
|
||||
|
||||
class PlaylistLayeringTest : public AudioRegionTest
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (PlaylistLayeringTest);
|
||||
CPPUNIT_TEST (basicsTest);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "ardour/playlist.h"
|
||||
#include "ardour/region.h"
|
||||
#include "ardour/audioplaylist.h"
|
||||
|
|
@ -14,7 +32,7 @@ using namespace ARDOUR;
|
|||
void
|
||||
PlaylistReadTest::setUp ()
|
||||
{
|
||||
TestNeedingPlaylistAndRegions::setUp ();
|
||||
AudioRegionTest::setUp ();
|
||||
|
||||
_N = 1024;
|
||||
_buf = new Sample[_N];
|
||||
|
|
@ -23,8 +41,6 @@ PlaylistReadTest::setUp ()
|
|||
|
||||
_session->config.set_auto_xfade (false);
|
||||
|
||||
_apl = boost::dynamic_pointer_cast<AudioPlaylist> (_playlist);
|
||||
|
||||
for (int i = 0; i < _N; ++i) {
|
||||
_buf[i] = 0;
|
||||
}
|
||||
|
|
@ -37,9 +53,7 @@ PlaylistReadTest::tearDown ()
|
|||
delete[] _mbuf;
|
||||
delete[] _gbuf;
|
||||
|
||||
_apl.reset ();
|
||||
|
||||
TestNeedingPlaylistAndRegions::tearDown ();
|
||||
AudioRegionTest::tearDown ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -47,15 +61,13 @@ PlaylistReadTest::singleReadTest ()
|
|||
{
|
||||
/* Single-region read with fades */
|
||||
|
||||
boost::shared_ptr<AudioRegion> ar0 = boost::dynamic_pointer_cast<AudioRegion> (_region[0]);
|
||||
ar0->set_name ("ar0");
|
||||
_apl->add_region (ar0, 0);
|
||||
ar0->set_default_fade_in ();
|
||||
ar0->set_default_fade_out ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_out->back()->when);
|
||||
ar0->set_length (1024);
|
||||
_apl->read (_buf, _mbuf, _gbuf, 0, 256, 0);
|
||||
_audio_playlist->add_region (_ar[0], 0);
|
||||
_ar[0]->set_default_fade_in ();
|
||||
_ar[0]->set_default_fade_out ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_out->back()->when);
|
||||
_ar[0]->set_length (1024);
|
||||
_audio_playlist->read (_buf, _mbuf, _gbuf, 0, 256, 0);
|
||||
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
/* Note: this specific float casting is necessary so that the rounding
|
||||
|
|
@ -72,34 +84,38 @@ PlaylistReadTest::singleReadTest ()
|
|||
void
|
||||
PlaylistReadTest::overlappingReadTest ()
|
||||
{
|
||||
/* Overlapping read; ar0 and ar1 are both 1024 frames long, ar0 starts at 0,
|
||||
ar1 starts at 128. We test a read from 0 to 256, which should consist
|
||||
of the start of ar0, with its fade in, followed by ar1's fade in (mixed with ar0
|
||||
faded out with the inverse gain), and some more of ar1.
|
||||
/* Overlapping read; _ar[0] and _ar[1] are both 1024 frames long, _ar[0] starts at 0,
|
||||
_ar[1] starts at 128. We test a read from 0 to 256, which should consist
|
||||
of the start of _ar[0], with its fade in, followed by _ar[1]'s fade in (mixed with _ar[0]
|
||||
faded out with the inverse gain), and some more of _ar[1].
|
||||
*/
|
||||
|
||||
boost::shared_ptr<AudioRegion> ar0 = boost::dynamic_pointer_cast<AudioRegion> (_region[0]);
|
||||
ar0->set_name ("ar0");
|
||||
_apl->add_region (ar0, 0);
|
||||
ar0->set_default_fade_in ();
|
||||
ar0->set_default_fade_out ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_out->back()->when);
|
||||
ar0->set_length (1024);
|
||||
_audio_playlist->add_region (_ar[0], 0);
|
||||
_ar[0]->set_default_fade_in ();
|
||||
_ar[0]->set_default_fade_out ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_out->back()->when);
|
||||
_ar[0]->set_length (1024);
|
||||
|
||||
boost::shared_ptr<AudioRegion> ar1 = boost::dynamic_pointer_cast<AudioRegion> (_region[1]);
|
||||
ar1->set_name ("ar1");
|
||||
_apl->add_region (ar1, 128);
|
||||
ar1->set_default_fade_in ();
|
||||
ar1->set_default_fade_out ();
|
||||
/* Note: these are ordinary fades, not xfades */
|
||||
CPPUNIT_ASSERT_EQUAL (false, _ar[0]->fade_in_is_xfade());
|
||||
CPPUNIT_ASSERT_EQUAL (false, _ar[0]->fade_out_is_xfade());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar1->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar1->_fade_out->back()->when);
|
||||
_audio_playlist->add_region (_ar[1], 128);
|
||||
_ar[1]->set_default_fade_in ();
|
||||
_ar[1]->set_default_fade_out ();
|
||||
|
||||
ar1->set_length (1024);
|
||||
_apl->read (_buf, _mbuf, _gbuf, 0, 256, 0);
|
||||
/* Note: these are ordinary fades, not xfades */
|
||||
CPPUNIT_ASSERT_EQUAL (false, _ar[1]->fade_in_is_xfade());
|
||||
CPPUNIT_ASSERT_EQUAL (false, _ar[1]->fade_out_is_xfade());
|
||||
|
||||
/* ar0's fade in */
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[1]->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[1]->_fade_out->back()->when);
|
||||
|
||||
_ar[1]->set_length (1024);
|
||||
_audio_playlist->read (_buf, _mbuf, _gbuf, 0, 256, 0);
|
||||
|
||||
/* _ar[0]'s fade in */
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
/* Note: this specific float casting is necessary so that the rounding
|
||||
is done here the same as it is done in AudioPlaylist; the gain factor
|
||||
|
|
@ -109,12 +125,12 @@ PlaylistReadTest::overlappingReadTest ()
|
|||
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * float (i / (double) 63)), _buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* bit of ar0 */
|
||||
/* bit of _ar[0] */
|
||||
for (int i = 64; i < 128; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL (i, int (_buf[i]));
|
||||
}
|
||||
|
||||
/* ar1's fade in with faded-out ar0 */
|
||||
/* _ar[1]'s fade in with faded-out _ar[0] */
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
/* Similar carry-on to above with float rounding */
|
||||
float const from_ar0 = (128 + i) * float (1 - (i / (double) 63));
|
||||
|
|
@ -126,29 +142,25 @@ PlaylistReadTest::overlappingReadTest ()
|
|||
void
|
||||
PlaylistReadTest::transparentReadTest ()
|
||||
{
|
||||
boost::shared_ptr<AudioRegion> ar0 = boost::dynamic_pointer_cast<AudioRegion> (_region[0]);
|
||||
ar0->set_name ("ar0");
|
||||
_apl->add_region (ar0, 0);
|
||||
ar0->set_default_fade_in ();
|
||||
ar0->set_default_fade_out ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_out->back()->when);
|
||||
ar0->set_length (1024);
|
||||
_audio_playlist->add_region (_ar[0], 0);
|
||||
_ar[0]->set_default_fade_in ();
|
||||
_ar[0]->set_default_fade_out ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_out->back()->when);
|
||||
_ar[0]->set_length (1024);
|
||||
|
||||
boost::shared_ptr<AudioRegion> ar1 = boost::dynamic_pointer_cast<AudioRegion> (_region[1]);
|
||||
ar1->set_name ("ar1");
|
||||
_apl->add_region (ar1, 0);
|
||||
ar1->set_default_fade_in ();
|
||||
ar1->set_default_fade_out ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar1->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar1->_fade_out->back()->when);
|
||||
ar1->set_length (1024);
|
||||
ar1->set_opaque (false);
|
||||
_audio_playlist->add_region (_ar[1], 0);
|
||||
_ar[1]->set_default_fade_in ();
|
||||
_ar[1]->set_default_fade_out ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[1]->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[1]->_fade_out->back()->when);
|
||||
_ar[1]->set_length (1024);
|
||||
_ar[1]->set_opaque (false);
|
||||
|
||||
_apl->read (_buf, _mbuf, _gbuf, 0, 1024, 0);
|
||||
_audio_playlist->read (_buf, _mbuf, _gbuf, 0, 1024, 0);
|
||||
|
||||
/* ar0 and ar1 fade-ins; ar1 is on top, but it is transparent, so
|
||||
its fade in will not affect ar0; ar0 will just fade in by itself,
|
||||
/* _ar[0] and _ar[1] fade-ins; _ar[1] is on top, but it is transparent, so
|
||||
its fade in will not affect _ar[0]; _ar[0] will just fade in by itself,
|
||||
and the two will be mixed.
|
||||
*/
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
|
|
@ -158,12 +170,12 @@ PlaylistReadTest::transparentReadTest ()
|
|||
CPPUNIT_ASSERT_DOUBLES_EQUAL (ar0 + ar1, _buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* ar0 and ar1 bodies, mixed */
|
||||
/* _ar[0] and _ar[1] bodies, mixed */
|
||||
for (int i = 64; i < (1024 - 64); ++i) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * 2), _buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* ar0 and ar1 fade-outs, mixed */
|
||||
/* _ar[0] and _ar[1] fade-outs, mixed */
|
||||
for (int i = (1024 - 64); i < 1024; ++i) {
|
||||
/* Ardour fades out from 1 to VERY_SMALL_SIGNAL, which is 0.0000001,
|
||||
so this fade out expression is a little long-winded.
|
||||
|
|
@ -181,23 +193,21 @@ PlaylistReadTest::transparentReadTest ()
|
|||
void
|
||||
PlaylistReadTest::miscReadTest ()
|
||||
{
|
||||
boost::shared_ptr<AudioRegion> ar0 = boost::dynamic_pointer_cast<AudioRegion> (_region[0]);
|
||||
ar0->set_name ("ar0");
|
||||
_apl->add_region (ar0, 0);
|
||||
ar0->set_default_fade_in ();
|
||||
ar0->set_default_fade_out ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_out->back()->when);
|
||||
ar0->set_length (128);
|
||||
_audio_playlist->add_region (_ar[0], 0);
|
||||
_ar[0]->set_default_fade_in ();
|
||||
_ar[0]->set_default_fade_out ();
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_in->back()->when);
|
||||
CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_out->back()->when);
|
||||
_ar[0]->set_length (128);
|
||||
|
||||
/* Read for just longer than the region */
|
||||
_apl->read (_buf, _mbuf, _gbuf, 0, 129, 0);
|
||||
_audio_playlist->read (_buf, _mbuf, _gbuf, 0, 129, 0);
|
||||
|
||||
/* Read for much longer than the region */
|
||||
_apl->read (_buf, _mbuf, _gbuf, 0, 1024, 0);
|
||||
_audio_playlist->read (_buf, _mbuf, _gbuf, 0, 1024, 0);
|
||||
|
||||
/* Read one sample */
|
||||
_apl->read (_buf, _mbuf, _gbuf, 53, 54, 0);
|
||||
_audio_playlist->read (_buf, _mbuf, _gbuf, 53, 54, 0);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -219,46 +229,42 @@ PlaylistReadTest::check_staircase (Sample* b, int offset, int N)
|
|||
void
|
||||
PlaylistReadTest::enclosedTransparentReadTest ()
|
||||
{
|
||||
boost::shared_ptr<AudioRegion> ar0 = boost::dynamic_pointer_cast<AudioRegion> (_region[0]);
|
||||
ar0->set_name ("ar0");
|
||||
_apl->add_region (ar0, 256);
|
||||
_audio_playlist->add_region (_ar[0], 256);
|
||||
/* These calls will result in a 64-sample fade */
|
||||
ar0->set_fade_in_length (0);
|
||||
ar0->set_fade_out_length (0);
|
||||
ar0->set_length (256);
|
||||
_ar[0]->set_fade_in_length (0);
|
||||
_ar[0]->set_fade_out_length (0);
|
||||
_ar[0]->set_length (256);
|
||||
|
||||
boost::shared_ptr<AudioRegion> ar1 = boost::dynamic_pointer_cast<AudioRegion> (_region[1]);
|
||||
ar1->set_name ("ar1");
|
||||
_apl->add_region (ar1, 0);
|
||||
_audio_playlist->add_region (_ar[1], 0);
|
||||
/* These calls will result in a 64-sample fade */
|
||||
ar1->set_fade_in_length (0);
|
||||
ar1->set_fade_out_length (0);
|
||||
ar1->set_length (1024);
|
||||
ar1->set_opaque (false);
|
||||
_ar[1]->set_fade_in_length (0);
|
||||
_ar[1]->set_fade_out_length (0);
|
||||
_ar[1]->set_length (1024);
|
||||
_ar[1]->set_opaque (false);
|
||||
|
||||
_apl->read (_buf, _mbuf, _gbuf, 0, 1024, 0);
|
||||
_audio_playlist->read (_buf, _mbuf, _gbuf, 0, 1024, 0);
|
||||
|
||||
/* First 64 samples should just be ar1, faded in */
|
||||
/* First 64 samples should just be _ar[1], faded in */
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * float (i / 63.0)), _buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* Then some of ar1 with no fade */
|
||||
/* Then some of _ar[1] with no fade */
|
||||
for (int i = 64; i < 256; ++i) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (i, _buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* Then ar1 + ar0 (faded in) for 64 samples */
|
||||
/* Then _ar[1] + _ar[0] (faded in) for 64 samples */
|
||||
for (int i = 256; i < (256 + 64); ++i) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (i + float ((i - 256) * float ((i - 256) / 63.0)), _buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* Then ar1 + ar0 for 128 samples */
|
||||
/* Then _ar[1] + _ar[0] for 128 samples */
|
||||
for (int i = (256 + 64); i < (256 + 64 + 128); ++i) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (i + i - (256 + 64) + 64, _buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* Then ar1 + ar0 (faded out) for 64 samples */
|
||||
/* Then _ar[1] + _ar[0] (faded out) for 64 samples */
|
||||
for (int i = (256 + 64 + 128); i < 512; ++i) {
|
||||
float const ar0_without_fade = i - 256;
|
||||
/* See above regarding VERY_SMALL_SIGNAL SNAFU */
|
||||
|
|
@ -266,12 +272,12 @@ PlaylistReadTest::enclosedTransparentReadTest ()
|
|||
CPPUNIT_ASSERT_DOUBLES_EQUAL (i + float (ar0_without_fade * fade), _buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* Then just ar1 for a while */
|
||||
/* Then just _ar[1] for a while */
|
||||
for (int i = 512; i < (1024 - 64); ++i) {
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL (i, _buf[i], 1e-16);
|
||||
}
|
||||
|
||||
/* And finally ar1's fade out */
|
||||
/* And finally _ar[1]'s fade out */
|
||||
for (int i = (1024 - 64); i < 1024; ++i) {
|
||||
/* See above regarding VERY_SMALL_SIGNAL SNAFU */
|
||||
float const fade = (((double) 1 - 0.0000001) / 63) * (1023 - i) + 0.0000001;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,25 @@
|
|||
#include "ardour/types.h"
|
||||
#include "test_needing_playlist_and_regions.h"
|
||||
/*
|
||||
Copyright (C) 2012 Paul Davis
|
||||
|
||||
class PlaylistReadTest : public TestNeedingPlaylistAndRegions
|
||||
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.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "ardour/types.h"
|
||||
#include "audio_region_test.h"
|
||||
|
||||
class PlaylistReadTest : public AudioRegionTest
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (PlaylistReadTest);
|
||||
CPPUNIT_TEST (singleReadTest);
|
||||
|
|
@ -26,7 +44,6 @@ private:
|
|||
ARDOUR::Sample* _buf;
|
||||
ARDOUR::Sample* _mbuf;
|
||||
float* _gbuf;
|
||||
boost::shared_ptr<ARDOUR::AudioPlaylist> _apl;
|
||||
|
||||
void check_staircase (ARDOUR::Sample *, int, int);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#include "test_globals.h"
|
||||
|
||||
int const Fs = 44100;
|
||||
int const sinusoid_frequency = 440;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
|
||||
extern int const Fs;
|
||||
extern int const sinusoid_frequency;
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
#include "pbd/filesystem.h"
|
||||
#include "ardour/playlist_factory.h"
|
||||
#include "ardour/source_factory.h"
|
||||
#include "ardour/region.h"
|
||||
#include "ardour/region_factory.h"
|
||||
#include "ardour/sndfilesource.h"
|
||||
#include "test_needing_playlist_and_regions.h"
|
||||
#include "test_globals.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
|
||||
void
|
||||
TestNeedingPlaylistAndRegions::setUp ()
|
||||
{
|
||||
TestNeedingSession::setUp ();
|
||||
|
||||
/* This is important, otherwise createWritable will mark the source immutable (hence unwritable) */
|
||||
unlink ("libs/ardour/test/test.wav");
|
||||
string const test_wav_path = "libs/ardour/test/test.wav";
|
||||
_playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test");
|
||||
_source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, Fs);
|
||||
|
||||
/* Write a staircase to the source */
|
||||
|
||||
boost::shared_ptr<SndFileSource> s = boost::dynamic_pointer_cast<SndFileSource> (_source);
|
||||
assert (s);
|
||||
|
||||
int const signal_length = 4096;
|
||||
|
||||
Sample staircase[signal_length];
|
||||
for (int i = 0; i < signal_length; ++i) {
|
||||
staircase[i] = i;
|
||||
}
|
||||
|
||||
s->write (staircase, signal_length);
|
||||
|
||||
PropertyList plist;
|
||||
plist.add (Properties::start, 0);
|
||||
plist.add (Properties::length, 100);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
_region[i] = RegionFactory::create (_source, plist);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TestNeedingPlaylistAndRegions::tearDown ()
|
||||
{
|
||||
_playlist.reset ();
|
||||
_source.reset ();
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
_region[i].reset ();
|
||||
}
|
||||
|
||||
TestNeedingSession::tearDown ();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#include <boost/shared_ptr.hpp>
|
||||
#include "test_needing_session.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class Playlist;
|
||||
class Source;
|
||||
class Region;
|
||||
}
|
||||
|
||||
class TestNeedingPlaylistAndRegions : public TestNeedingSession
|
||||
{
|
||||
public:
|
||||
virtual void setUp ();
|
||||
virtual void tearDown ();
|
||||
|
||||
protected:
|
||||
boost::shared_ptr<ARDOUR::Playlist> _playlist;
|
||||
boost::shared_ptr<ARDOUR::Source> _source;
|
||||
boost::shared_ptr<ARDOUR::Region> _region[16];
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue