#include <ardour/location.h>
#include <ardour/audioplaylist.h>
#include <ardour/audioregion.h>
-#include <ardour/region.h>
+#include <ardour/midi_region.h>
#include <ardour/session_route.h>
#include <ardour/tempo.h>
#include <ardour/utils.h>
while (i != selection->regions.end() && boost::dynamic_pointer_cast<AudioRegion>((*i)->region()) == 0) {
++i;
}
- bool const have_selected_audio_region = (i != selection->regions.end());
+ const bool have_selected_audio_region = (i != selection->regions.end());
if (have_selected_audio_region) {
items.push_back (MenuElem (_("Normalize"), mem_fun (*this, &Editor::normalize_regions)));
}
- items.push_back (MenuElem (_("Reverse"), mem_fun(*this, &Editor::reverse_regions)));
- items.push_back (SeparatorElem());
+ /* Find out if we have a selected MIDI region */
+ i = selection->regions.begin();
+ while (i != selection->regions.end() && boost::dynamic_pointer_cast<MidiRegion>((*i)->region()) == 0) {
+ ++i;
+ }
+ const bool have_selected_midi_region = (i != selection->regions.end());
+
+ if (have_selected_midi_region) {
+
+ items.push_back (MenuElem (_("Quantize"), mem_fun(*this, &Editor::quantize_regions)));
+ items.push_back (SeparatorElem());
+ }
/* range related stuff */
break;
case SnapToAThirtysecondBeat:
- start = session->tempo_map().round_to_beat_subdivision (start, 32);
- break;
+ start = session->tempo_map().round_to_beat_subdivision (start, 32);
+ break;
case SnapToASixteenthBeat:
- start = session->tempo_map().round_to_beat_subdivision (start, 16);
- break;
+ start = session->tempo_map().round_to_beat_subdivision (start, 16);
+ break;
case SnapToAEighthBeat:
- start = session->tempo_map().round_to_beat_subdivision (start, 8);
- break;
+ start = session->tempo_map().round_to_beat_subdivision (start, 8);
+ break;
case SnapToAQuarterBeat:
- start = session->tempo_map().round_to_beat_subdivision (start, 4);
- break;
+ start = session->tempo_map().round_to_beat_subdivision (start, 4);
+ break;
- case SnapToAThirdBeat:
- start = session->tempo_map().round_to_beat_subdivision (start, 3);
- break;
+ case SnapToAThirdBeat:
+ start = session->tempo_map().round_to_beat_subdivision (start, 3);
+ break;
case SnapToEditCursor:
start = edit_cursor->current_frame;
}
}
+double
+Editor::snap_length_beats (nframes_t start)
+{
+ if (!session) {
+ return 1.0;
+ }
+
+ const nframes64_t one_second = session->frame_rate();
+ const nframes64_t one_minute = session->frame_rate() * 60;
+ const nframes64_t one_smpte_second = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame());
+ nframes64_t one_smpte_minute = (nframes64_t)(rint(session->smpte_frames_per_second()) * session->frames_per_smpte_frame() * 60);
+ nframes64_t presnap = start;
+
+ /* FIXME: This could/should also work with non-tempo based snap settings (ie seconds) */
+
+ switch (snap_type) {
+ case SnapToBar:
+ return session->tempo_map().meter_at(start).beats_per_bar();
+
+ case SnapToBeat:
+ return 1.0;
+
+ case SnapToAThirtysecondBeat:
+ return 1.0 / (double)32.0;
+ break;
+
+ case SnapToASixteenthBeat:
+ return 1.0 / (double)16.0;
+ break;
+
+ case SnapToAEighthBeat:
+ return 1.0 / (double)8.0;
+ break;
+
+ case SnapToAQuarterBeat:
+ return 1.0 / (double)4.0;
+ break;
+
+ case SnapToAThirdBeat:
+ return 1.0 / (double)3.0;
+
+ default:
+ return 1.0;
+ }
+}
+
void
Editor::setup_toolbar ()
{
class TempoSection;
class NamedSelection;
class Session;
- class AudioFilter;
+ class Filter;
class Crossfade;
class ChanCount;
}
/* snapshots */
- Gtk::ScrolledWindow snapshot_display_scroller;
+ Gtk::ScrolledWindow snapshot_display_scroller;
struct SnapshotDisplayModelColumns : public Gtk::TreeModel::ColumnRecord {
SnapshotDisplayModelColumns() {
add (visible_name);
void reverse_regions ();
void normalize_regions ();
void denormalize_regions ();
+ void quantize_regions ();
void audition_region_from_region_list ();
void hide_region_from_region_list ();
snap_to (first64, direction, for_mark);
first = (nframes_t) first64;
}
+
+ double snap_length_beats (nframes_t start);
uint32_t bbt_beat_subdivision;
/* audio filters */
- void apply_filter (ARDOUR::AudioFilter&, string cmd);
+ void apply_filter (ARDOUR::Filter&, string cmd);
/* handling cleanup */
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "normalize-region", _("Normalize Regions"), mem_fun(*this, &Editor::normalize_regions));
ActionManager::session_sensitive_actions.push_back (act);
+ act = ActionManager::register_action (editor_actions, "quantize-region", _("Quantize Regions"), mem_fun(*this, &Editor::quantize_regions));
+ ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "crop", _("crop"), mem_fun(*this, &Editor::crop_region_to_selection));
ActionManager::session_sensitive_actions.push_back (act);
act = ActionManager::register_action (editor_actions, "insert-chunk", _("Insert Chunk"), bind (mem_fun(*this, &Editor::paste_named_selection), 1.0f));
#include <ardour/region_factory.h>
#include <ardour/playlist_factory.h>
#include <ardour/reverse.h>
+#include <ardour/quantize.h>
#include "ardour_ui.h"
#include "editor.h"
#include "automation_time_axis.h"
#include "streamview.h"
#include "audio_region_view.h"
+#include "midi_region_view.h"
#include "rgb_macros.h"
#include "selection_templates.h"
#include "selection.h"
apply_filter (rev, _("reverse regions"));
}
+
+void
+Editor::quantize_regions ()
+{
+ if (!session) {
+ return;
+ }
+
+ // FIXME: varying meter?
+ Quantize quant (*session, snap_length_beats(0));
+ apply_filter (quant, _("quantize regions"));
+}
+
void
-Editor::apply_filter (AudioFilter& filter, string command)
+Editor::apply_filter (Filter& filter, string command)
{
if (selection->regions.empty()) {
return;
track_canvas.get_window()->set_cursor (*wait_cursor);
gdk_flush ();
+ /* this is ugly. */
for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
- AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
- if (!arv)
- continue;
+ RegionSelection::iterator tmp = r;
+ ++tmp;
- boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
+ MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
+ if (mrv) {
+ if (mrv->midi_region()->apply(filter) == 0) {
+ mrv->redisplay_model();
+ }
+ }
- RegionSelection::iterator tmp;
-
- tmp = r;
- ++tmp;
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
+ if (arv) {
+ boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
- if (arv->audio_region()->apply (filter) == 0) {
+ if (arv->audio_region()->apply (filter) == 0) {
- XMLNode &before = playlist->get_state();
- playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
- XMLNode &after = playlist->get_state();
- session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
- } else {
- goto out;
+ XMLNode &before = playlist->get_state();
+ playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
+ XMLNode &after = playlist->get_state();
+ session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+ } else {
+ goto out;
+ }
}
r = tmp;
}
}
-void
-MidiRegionView::show_region_editor ()
-{
- cerr << "No MIDI region editor." << endl;
-}
-
GhostRegion*
MidiRegionView::add_ghost (AutomationTimeAxisView& atv)
{
{ return midi_view()->midi_view(); }
void set_y_position_and_height (double, double);
-
- void show_region_editor ();
+
+ void redisplay_model();
GhostRegion* add_ghost (AutomationTimeAxisView&);
private:
- void redisplay_model();
void clear_events();
bool canvas_event(GdkEvent* ev);
/** Snap a value according to the current snap setting. */
virtual void snap_to (nframes_t& first, int32_t direction = 0, bool for_mark = false) = 0;
+
+ /** Get the current snap value in beats */
+ virtual double snap_length_beats (nframes_t start) = 0;
/** Undo some transactions.
* @param n Number of transactions to undo.
bool set_position(nframes_t pos, void* src, double* delta = 0);
void fake_set_opaque (bool yn);
- virtual void show_region_editor () = 0;
+ virtual void show_region_editor () {}
virtual void hide_region_editor();
virtual void region_changed (ARDOUR::Change);
meter.cc
amp.cc
panner.cc
+filter.cc
audiofilesource.cc
-audiofilter.cc
audioregion.cc
audiosource.cc
midi_source.cc
region.cc
region_factory.cc
reverse.cc
+quantize.cc
route.cc
route_group.cc
send.cc
+++ /dev/null
-/*
- Copyright (C) 2004 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_audiofilter_h__
-#define __ardour_audiofilter_h__
-
-#include <vector>
-#include <ardour/audioregion.h>
-
-namespace ARDOUR {
-
-class AudioRegion;
-class Session;
-
-class AudioFilter {
-
- public:
- AudioFilter (ARDOUR::Session& s)
- : session (s){}
- virtual ~AudioFilter() {}
-
- virtual int run (boost::shared_ptr<ARDOUR::AudioRegion>) = 0;
- std::vector<boost::shared_ptr<ARDOUR::AudioRegion> > results;
-
- protected:
- ARDOUR::Session& session;
-
- int make_new_sources (boost::shared_ptr<ARDOUR::AudioRegion>, ARDOUR::SourceList&);
- int finish (boost::shared_ptr<ARDOUR::AudioRegion>, ARDOUR::SourceList&);
-};
-
-} /* namespace */
-
-#endif /* __ardour_audiofilter_h__ */
class Route;
class Playlist;
class Session;
-class AudioFilter;
+class Filter;
class AudioSource;
class AudioRegion : public Region
int separate_by_channel (ARDOUR::Session&, vector<boost::shared_ptr<AudioRegion> >&) const;
- /* filter */
-
- int apply (AudioFilter&);
-
/* export */
int exportme (ARDOUR::Session&, ARDOUR::AudioExportSpecification&);
--- /dev/null
+/*
+ Copyright (C) 2007 Paul Davis
+ Author: Dave Robillard
+
+ 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_filter_h__
+#define __ardour_filter_h__
+
+#include <vector>
+#include <ardour/region.h>
+
+namespace ARDOUR {
+
+class Region;
+class Session;
+
+class Filter {
+
+ public:
+ virtual ~Filter() {}
+
+ virtual int run (boost::shared_ptr<ARDOUR::Region>) = 0;
+ std::vector<boost::shared_ptr<ARDOUR::Region> > results;
+
+ protected:
+ Filter (ARDOUR::Session& s) : session(s) {}
+
+ int make_new_sources (boost::shared_ptr<ARDOUR::Region>, ARDOUR::SourceList&);
+ int finish (boost::shared_ptr<ARDOUR::Region>, ARDOUR::SourceList&);
+
+ ARDOUR::Session& session;
+};
+
+} /* namespace */
+
+#endif /* __ardour_filter_h__ */
namespace ARDOUR {
class Playlist;
+class Filter;
enum RegionEditState {
EditChangesNothing = 0,
void set_opaque (bool yn);
void set_locked (bool yn);
void set_position_locked (bool yn);
+
+ int apply (Filter&);
virtual uint32_t read_data_count() const { return _read_data_count; }
#ifndef __ardour_reverse_h__
#define __ardour_reverse_h__
-#include <ardour/audiofilter.h>
+#include <ardour/filter.h>
namespace ARDOUR {
-class Reverse : public AudioFilter {
+class Reverse : public Filter {
public:
Reverse (ARDOUR::Session&);
~Reverse ();
- int run (boost::shared_ptr<ARDOUR::AudioRegion>);
+ int run (boost::shared_ptr<ARDOUR::Region>);
};
} /* namespace */
int region_name (string& result, string base = string(""), bool newlevel = false) const;
string new_region_name (string);
- string path_from_region_name (string name, string identifier);
+ string path_from_region_name (DataType type, string name, string identifier);
boost::shared_ptr<Region> find_whole_file_parent (boost::shared_ptr<Region const>);
+++ /dev/null
-/*
- Copyright (C) 2004 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 <time.h>
-#include <cerrno>
-
-#include <pbd/basename.h>
-#include <ardour/sndfilesource.h>
-#include <ardour/session.h>
-#include <ardour/audioregion.h>
-#include <ardour/audiofilter.h>
-#include <ardour/region_factory.h>
-#include <ardour/source_factory.h>
-
-#include "i18n.h"
-
-using namespace ARDOUR;
-using namespace PBD;
-
-int
-AudioFilter::make_new_sources (boost::shared_ptr<AudioRegion> region, SourceList& nsrcs)
-{
- vector<string> names = region->master_source_names();
-
- for (uint32_t i = 0; i < region->n_channels(); ++i) {
-
- string path = session.path_from_region_name (PBD::basename_nosuffix (names[i]), string (""));
-
- if (path.length() == 0) {
- error << string_compose (_("audiofilter: error creating name for new audio file based on %1"), region->name())
- << endmsg;
- return -1;
- }
-
- try {
- nsrcs.push_back (boost::dynamic_pointer_cast<AudioSource> (
- SourceFactory::createWritable (DataType::AUDIO, session, path, false, session.frame_rate())));
- }
-
- catch (failed_constructor& err) {
- error << string_compose (_("audiofilter: error creating new audio file %1 (%2)"), path, strerror (errno)) << endmsg;
- return -1;
- }
- }
-
- return 0;
-}
-
-int
-AudioFilter::finish (boost::shared_ptr<AudioRegion> region, SourceList& nsrcs)
-{
- string region_name;
-
- /* update headers on new sources */
-
- time_t xnow;
- struct tm* now;
-
- time (&xnow);
- now = localtime (&xnow);
-
- for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
- boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*si);
- if (afs) {
- afs->update_header (region->position(), *now, xnow);
- afs->mark_immutable ();
- }
- }
-
- /* create a new region */
-
- region_name = session.new_region_name (region->name());
- results.clear ();
- results.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (nsrcs, 0, region->length(), region_name, 0,
- Region::Flag (Region::WholeFile|Region::DefaultFlags))));
-
- return 0;
-}
#include <ardour/gain.h>
#include <ardour/dB.h>
#include <ardour/playlist.h>
-#include <ardour/audiofilter.h>
#include <ardour/audiofilesource.h>
#include <ardour/region_factory.h>
#include <ardour/runtime_functions.h>
return 0;
}
-int
-AudioRegion::apply (AudioFilter& filter)
-{
- boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (shared_from_this());
- return filter.run (ar);
-}
-
nframes_t
AudioRegion::read_raw_internal (Sample* buf, nframes_t pos, nframes_t cnt) const
{
--- /dev/null
+/*
+ Copyright (C) 2004-2007 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 <time.h>
+#include <cerrno>
+
+#include <pbd/basename.h>
+#include <ardour/sndfilesource.h>
+#include <ardour/smf_source.h>
+#include <ardour/session.h>
+#include <ardour/region.h>
+#include <ardour/filter.h>
+#include <ardour/region_factory.h>
+#include <ardour/source_factory.h>
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+
+int
+Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs)
+{
+ vector<string> names = region->master_source_names();
+
+ for (uint32_t i = 0; i < region->n_channels(); ++i) {
+
+ string path = session.path_from_region_name (region->data_type(),
+ PBD::basename_nosuffix (names[i]), string (""));
+
+ if (path.length() == 0) {
+ error << string_compose (_("filter: error creating name for new file based on %1"), region->name())
+ << endmsg;
+ return -1;
+ }
+
+ try {
+ nsrcs.push_back (boost::dynamic_pointer_cast<Source> (
+ SourceFactory::createWritable (region->data_type(), session, path, false, session.frame_rate())));
+ }
+
+ catch (failed_constructor& err) {
+ error << string_compose (_("filter: error creating new file %1 (%2)"), path, strerror (errno)) << endmsg;
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+Filter::finish (boost::shared_ptr<Region> region, SourceList& nsrcs)
+{
+ string region_name;
+
+ /* update headers on new sources */
+
+ time_t xnow;
+ struct tm* now;
+
+ time (&xnow);
+ now = localtime (&xnow);
+
+ /* this is ugly. */
+ for (SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*si);
+ if (afs) {
+ afs->update_header (region->position(), *now, xnow);
+ afs->mark_immutable ();
+ }
+
+ boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource>(*si);
+ if (smfs) {
+ smfs->update_header (region->position(), *now, xnow);
+ smfs->flush_footer ();
+ }
+ }
+
+ /* create a new region */
+
+ region_name = session.new_region_name (region->name());
+ results.clear ();
+ results.push_back (RegionFactory::create (nsrcs, 0, region->length(), region_name, 0,
+ Region::Flag (Region::WholeFile|Region::DefaultFlags)));
+
+ return 0;
+}
+
+
#include <ardour/session.h>
#include <ardour/source.h>
#include <ardour/region_factory.h>
+#include <ardour/filter.h>
#include "i18n.h"
return boost::shared_ptr<Region>();
}
+int
+Region::apply (Filter& filter)
+{
+ return filter.run (shared_from_this());
+}
+
+
using namespace ARDOUR;
Reverse::Reverse (Session& s)
- : AudioFilter (s)
+ : Filter (s)
{
}
}
int
-Reverse::run (boost::shared_ptr<AudioRegion> region)
+Reverse::run (boost::shared_ptr<Region> r)
{
SourceList nsrcs;
SourceList::iterator si;
nframes_t to_read;
int ret = -1;
+ boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion>(r);
+ if (!region)
+ return ret;
+
/* create new sources */
if (make_new_sources (region, nsrcs)) {
}
string
-Session::path_from_region_name (string name, string identifier)
+Session::path_from_region_name (DataType type, string name, string identifier)
{
char buf[PATH_MAX+1];
uint32_t n;
SessionDirectory sdir(get_best_session_directory_for_new_source());
- string sound_dir = sdir.sound_path().to_string();
+ string sound_dir = ((type == DataType::AUDIO)
+ ? sdir.sound_path().to_string()
+ : sdir.midi_path().to_string());
+
+ string ext = ((type == DataType::AUDIO) ? ".wav" : ".mid");
for (n = 0; n < 999999; ++n) {
if (identifier.length()) {
- snprintf (buf, sizeof(buf), "%s/%s%s%" PRIu32 ".wav", sound_dir.c_str(), name.c_str(),
- identifier.c_str(), n);
+ snprintf (buf, sizeof(buf), "%s/%s%s%" PRIu32 "%s", sound_dir.c_str(), name.c_str(),
+ identifier.c_str(), n, ext.c_str());
} else {
- snprintf (buf, sizeof(buf), "%s/%s-%" PRIu32 ".wav", sound_dir.c_str(), name.c_str(), n);
+ snprintf (buf, sizeof(buf), "%s/%s-%" PRIu32 "%s", sound_dir.c_str(), name.c_str(),
+ n, ext.c_str());
}
if (!Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
rstr = names[i];
}
- string path = path_from_region_name (PBD::basename_nosuffix (rstr), ident);
+ string path = path_from_region_name (DataType::AUDIO, PBD::basename_nosuffix (rstr), ident);
if (path.length() == 0) {
error << string_compose (_("tempoize: error creating name for new audio file based on %1"), tsr.region->name())