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:
Paul Davis 2012-06-14 01:09:40 +00:00
parent 2b1fdfe815
commit 129dcd7f97
130 changed files with 2870 additions and 1065 deletions

View file

@ -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"/>

View file

@ -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;
}

View file

@ -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 ();

View file

@ -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 ()
{

View file

@ -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 */

View file

@ -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));

View file

@ -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;
}

View file

@ -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

View file

@ -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 ()
{

View file

@ -62,7 +62,6 @@ private:
void end_touch();
void value_changed();
void automation_state_changed();
bool _ignore_change;
boost::shared_ptr<ARDOUR::Automatable> _printer;

View file

@ -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 ();

View file

@ -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()

View file

@ -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();

View file

@ -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;
}

View file

@ -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;

View file

@ -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")

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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 ();

View file

@ -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;

View file

@ -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) {

View file

@ -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 ();
}

View file

@ -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);

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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>";

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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);
};

View file

@ -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());

View file

@ -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 ());
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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 ();
}

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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 {

View file

@ -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__ */

View file

@ -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));
}

View file

@ -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

View file

@ -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 {

View file

@ -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;

View file

@ -613,6 +613,8 @@ StreamView::update_contents_height ()
break;
}
}
ContentsHeightChanged (); /* EMIT SIGNAL */
}
void

View file

@ -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);

View file

@ -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 &lt; and &gt; respectively to make < > display correctly in markup strings */
string
escape_angled_brackets (string const & s)
{
string o = s;
boost::replace_all (o, "<", "&lt;");
boost::replace_all (o, ">", "&gt;");
return o;
}
Gdk::Color
unique_random_color (list<Gdk::Color>& used_colors)
{

View file

@ -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> &);

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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;

View file

@ -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 */

View 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__ */

View file

@ -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.
*/

View file

@ -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:

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View 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);
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);

View file

@ -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 */

View file

@ -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()
{

View file

@ -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>();
}

View file

@ -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 */

View file

@ -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());
}

View file

@ -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 ();

View file

@ -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
}

View 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]));
}
}

View 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);
};

View file

@ -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 ();
}

View file

@ -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];
};

View 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 ();
}

View 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 ();
};

View file

@ -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 ()

View file

@ -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);

View file

@ -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 ());
}

View file

@ -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);

View file

@ -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;

View file

@ -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);
};

View file

@ -1,4 +1,3 @@
#include "test_globals.h"
int const Fs = 44100;
int const sinusoid_frequency = 440;

View file

@ -1,3 +1,2 @@
extern int const Fs;
extern int const sinusoid_frequency;

View file

@ -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 ();
}

View file

@ -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