ardour
quantize.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2004 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 #include <cmath>
20 
21 #include "pbd/basename.h"
22 
23 #include "ardour/quantize.h"
24 #include "ardour/midi_model.h"
25 
26 #include "i18n.h"
27 
28 using namespace std;
29 using namespace PBD;
30 using namespace ARDOUR;
31 
38 Quantize::Quantize (bool snap_start, bool snap_end,
39  double start_grid, double end_grid,
40  float strength, float swing, float threshold)
41  : _snap_start (snap_start)
42  , _snap_end (snap_end)
43  , _start_grid(start_grid)
44  , _end_grid(end_grid)
45  , _strength (strength/100.0)
46  , _swing (swing/100.0)
47  , _threshold (threshold)
48 {
49 }
50 
52 {
53 }
54 
55 Command*
58  std::vector<Evoral::Sequence<Evoral::Beats>::Notes>& seqs)
59 {
60  /* TODO: Rewrite this to be precise with fixed point? */
61 
62  /* Calculate offset from start of model to next closest quantize step,
63  to quantize relative to actual session beats (etc.) rather than from the
64  start of the model.
65  */
66  const double round_pos = round(position.to_double() / _start_grid) * _start_grid;
67  const double offset = round_pos - position.to_double();
68 
69  bool even;
70  MidiModel::NoteDiffCommand* cmd = new MidiModel::NoteDiffCommand (model, "quantize");
71 
72  for (std::vector<Evoral::Sequence<Evoral::Beats>::Notes>::iterator s = seqs.begin(); s != seqs.end(); ++s) {
73 
74  even = false;
75 
76  /* TODO 'swing' probably requires a 2nd iteration:
77  * first quantize notes to the grid, then apply beat shift
78  */
79  for (Evoral::Sequence<MidiModel::TimeType>::Notes::iterator i = (*s).begin(); i != (*s).end(); ++i) {
80 
81  double new_start = round (((*i)->time().to_double() - offset) / _start_grid) * _start_grid + offset;
82  double new_end = round (((*i)->end_time().to_double() - offset) / _end_grid) * _end_grid + offset;
83 
84  if (_swing > 0.0 && !even) {
85 
86  double next_grid = new_start + _start_grid;
87 
88  /* find a spot 2/3 (* swing factor) of the way between the grid point
89  we would put this note at, and the nominal position of the next note.
90  */
91 
92  new_start = new_start + (2.0/3.0 * _swing * (next_grid - new_start));
93  new_end = new_end + (2.0/3.0 * _swing * (next_grid - new_start));
94 
95  } else if (_swing < 0.0 && !even) {
96 
97  double prev_grid = new_start - _start_grid;
98 
99  /* find a spot 2/3 (* swing factor) of the way between the grid point
100  we would put this note at, and the nominal position of the previous note.
101  */
102 
103  new_start = new_start - (2.0/3.0 * _swing * (new_start - prev_grid));
104  new_end = new_end - (2.0/3.0 * _swing * (new_start - prev_grid));
105 
106  }
107 
108  double delta = new_start - (*i)->time().to_double();
109 
110  if (fabs (delta) >= _threshold) {
111  if (_snap_start) {
112  delta *= _strength;
114  (*i)->time() + delta);
115  }
116  }
117 
118  if (_snap_end) {
119  delta = new_end - (*i)->end_time().to_double();
120 
121  if (fabs (delta) >= _threshold) {
122  Evoral::Beats new_dur(new_end - new_start);
123 
124  if (!new_dur) {
125  new_dur = Evoral::Beats(_end_grid);
126  }
127 
128  cmd->change ((*i), MidiModel::NoteDiffCommand::Length, new_dur);
129  }
130  }
131 
132  even = !even;
133  }
134  }
135 
136  return cmd;
137 }
std::multiset< NotePtr, EarlierNoteComparator > Notes
Definition: Sequence.hpp:153
double _end_grid
Definition: quantize.h:46
float _strength
Definition: quantize.h:47
Definition: Beats.hpp:239
Command * operator()(boost::shared_ptr< ARDOUR::MidiModel >, Evoral::Beats position, std::vector< Evoral::Sequence< Evoral::Beats >::Notes > &)
Definition: quantize.cc:56
Definition: amp.h:29
bool _snap_start
Definition: quantize.h:43
void change(const NotePtr note, Property prop, uint8_t new_value)
Definition: midi_model.h:109
double _start_grid
Definition: quantize.h:45
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
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
Definition: debug.h:30
double to_double() const
Definition: Beats.hpp:185
LIBEVORAL_API uint64_t Beats
float _threshold
Definition: quantize.h:49