ardour
midi_stretch.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 Paul Davis
3  Author: David Robillard
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 
21 #include "pbd/error.h"
22 
23 #include "ardour/midi_model.h"
24 #include "ardour/midi_region.h"
25 #include "ardour/midi_source.h"
26 #include "ardour/midi_stretch.h"
27 #include "ardour/types.h"
28 
29 #include "i18n.h"
30 
31 using namespace std;
32 using namespace ARDOUR;
33 using namespace PBD;
34 
35 MidiStretch::MidiStretch (Session& s, const TimeFXRequest& req)
36  : Filter (s)
37  , _request (req)
38 {
39 }
40 
42 {
43 }
44 
45 int
47 {
48  SourceList nsrcs;
49  char suffix[32];
50 
52  if (!region) {
53  return -1;
54  }
55 
56  /* the name doesn't need to be super-precise, but allow for 2 fractional
57  digits just to disambiguate close but not identical stretches.
58  */
59 
60  snprintf (suffix, sizeof (suffix), "@%d", (int) floor (_request.time_fraction * 100.0f));
61 
62  string new_name = region->name();
63  string::size_type at = new_name.find ('@');
64 
65  // remove any existing stretch indicator
66 
67  if (at != string::npos && at > 2) {
68  new_name = new_name.substr (0, at - 1);
69  }
70 
71  new_name += suffix;
72 
73  /* create new sources */
74 
75  if (make_new_sources (region, nsrcs, suffix))
76  return -1;
77 
79  {
80  Source::Lock lock(src->mutex());
81  src->load_model(lock);
82  }
83 
84  boost::shared_ptr<MidiModel> old_model = src->model();
85 
87  if (!new_src) {
88  error << _("MIDI stretch created non-MIDI source") << endmsg;
89  return -1;
90  }
91 
92  Glib::Threads::Mutex::Lock sl (new_src->mutex ());
93 
94  new_src->load_model(sl, true);
95  boost::shared_ptr<MidiModel> new_model = new_src->model();
96  new_model->start_write();
97 
98  /* Note: pass true into force_discrete for the begin() iterator so that the model doesn't
99  * do interpolation of controller data when we stretch.
100  */
102  i != old_model->end(); ++i) {
103  const MidiModel::TimeType new_time = i->time() * (double)_request.time_fraction;
104 
105  // FIXME: double copy
107  ev.set_time(new_time);
108  new_model->append(ev, Evoral::next_event_id());
109  }
110 
112  new_model->set_edited (true);
113 
114  new_src->copy_interpolation_from (src);
115 
116  const int ret = finish (region, nsrcs, new_name);
117 
118  results[0]->set_length((framecnt_t) floor (r->length() * _request.time_fraction));
119 
120  return ret;
121 }
122 
const TimeFXRequest & _request
Definition: midi_stretch.h:36
Glib::Threads::Mutex::Lock Lock
Definition: source.h:54
int make_new_sources(boost::shared_ptr< ARDOUR::Region >, ARDOUR::SourceList &, std::string suffix="")
Definition: filter.cc:42
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
void set_edited(bool yn)
Definition: Sequence.hpp:296
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
void end_write(StuckNoteOption, Time when=Time())
Definition: Sequence.cpp:631
#define _(Text)
Definition: i18n.h:11
boost::shared_ptr< MidiModel > model()
Definition: midi_source.h:168
int64_t framecnt_t
Definition: types.h:76
void start_write()
Definition: Sequence.cpp:613
void copy_interpolation_from(boost::shared_ptr< MidiSource >)
Definition: midi_source.cc:494
const const_iterator & end() const
Definition: Sequence.hpp:280
Definition: amp.h:29
LIBEVORAL_API event_id_t next_event_id()
Definition: Event.cpp:39
std::vector< boost::shared_ptr< ARDOUR::Region > > results
Definition: filter.h:41
Glib::Threads::Mutex & mutex()
Definition: source.h:105
void append(const Event< Time > &ev, Evoral::event_id_t evid)
Definition: Sequence.cpp:889
std::string name() const
const_iterator begin(Time t=Time(), bool force_discrete=false, const std::set< Evoral::Parameter > &f=std::set< Evoral::Parameter >(), const std::set< WeakNotePtr > *active_notes=NULL) const
Definition: Sequence.hpp:272
void set_time(Time)
Definition: debug.h:30
framecnt_t length() const
Definition: region.h:114
virtual void load_model(const Glib::Threads::Mutex::Lock &lock, bool force_reload=false)=0
boost::shared_ptr< MidiSource > midi_source(uint32_t n=0) const
Definition: midi_region.cc:390
int finish(boost::shared_ptr< ARDOUR::Region >, ARDOUR::SourceList &, std::string region_name="")
Definition: filter.cc:88
int run(boost::shared_ptr< ARDOUR::Region >, Progress *progress=0)
Definition: midi_stretch.cc:46
std::vector< boost::shared_ptr< Source > > SourceList
Definition: types.h:520