ardour
transform.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 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 #include <glib.h>
21 
22 #include "ardour/transform.h"
23 #include "ardour/midi_model.h"
24 
25 namespace ARDOUR {
26 
28  : _prog(prog)
29 {}
30 
31 Variant
33 {
34  if (stack.empty()) {
35  return Variant();
36  }
37 
38  const Variant top = stack.top();
39  stack.pop();
40  return top;
41 }
42 
43 Variant
45 {
46  switch (source) {
47  case NOWHERE:
48  return Variant();
49  case THIS_NOTE:
51  case PREV_NOTE:
52  if (!ctx.prev_note) {
53  return Variant();
54  }
56  case INDEX:
57  return Variant(Variant::INT, ctx.index);
58  case N_NOTES:
59  return Variant(Variant::INT, ctx.n_notes);
60  case LITERAL:
61  return value;
62  case RANDOM:
63  return Variant(g_random_double());
64  }
65 
66  return Variant();
67 }
68 
69 void
71 {
72  if (op == PUSH) {
73  const Variant a = arg.eval(ctx);
74  if (!!a) {
75  /* Argument evaluated to a value, push it to the stack. Otherwise,
76  there was a reference to the previous note, but this is the
77  first, so skip this operation and do nothing. */
78  ctx.stack.push(a);
79  }
80  return;
81  }
82 
83  // Pop operands off the stack
84  const Variant rhs = ctx.pop();
85  const Variant lhs = ctx.pop();
86  if (!lhs || !rhs) {
87  // Stack underflow (probably previous note reference), do nothing
88  return;
89  }
90 
91  // We can get away with just using double math and converting twice
92  double value = lhs.to_double();
93  switch (op) {
94  case ADD:
95  value += rhs.to_double();
96  break;
97  case SUB:
98  value -= rhs.to_double();
99  break;
100  case MULT:
101  value *= rhs.to_double();
102  break;
103  case DIV:
104  if (rhs.to_double() == 0.0) {
105  return; // Program will fail safely
106  }
107  value /= rhs.to_double();
108  break;
109  case MOD:
110  if (rhs.to_double() == 0.0) {
111  return; // Program will fail safely
112  }
113  value = fmod(value, rhs.to_double());
114  break;
115  default: break;
116  }
117 
118  // Push result on to the stack
119  ctx.stack.push(Variant(lhs.type(), value));
120 }
121 
122 Command*
125  std::vector<Notes>& seqs)
126 {
128 
129  Command* cmd = new Command(model, name());
130 
131  for (std::vector<Notes>::iterator s = seqs.begin(); s != seqs.end(); ++s) {
132  Context ctx;
133  ctx.n_notes = (*s).size();
134  for (Notes::const_iterator i = (*s).begin(); i != (*s).end(); ++i) {
135  const NotePtr note = *i;
136 
137  // Clear stack and run program
138  ctx.stack = std::stack<Variant>();
139  ctx.this_note = note;
140  for (std::list<Operation>::const_iterator o = _prog.ops.begin();
141  o != _prog.ops.end();
142  ++o) {
143  (*o).eval(ctx);
144  }
145 
146  // Result is on top of the stack
147  if (!ctx.stack.empty() && !!ctx.stack.top()) {
148  // Get the result from the top of the stack
149  Variant result = ctx.stack.top();
150  if (result.type() != Command::value_type(_prog.prop)) {
151  // Coerce to appropriate type
152  result = Variant(Command::value_type(_prog.prop),
153  result.to_double());
154  }
155 
156  // Apply change
157  cmd->change(note, _prog.prop, result);
158  }
159  // else error or reference to note before the first, skip
160 
161  // Move forward
162  ctx.prev_note = note;
163  ++ctx.index;
164  }
165  }
166 
167  return cmd;
168 }
169 
170 } // namespace ARDOUR
const Program _prog
Definition: transform.h:141
Property prop
Property to calculate.
Definition: transform.h:128
void eval(Context &context) const
Definition: transform.cc:70
double to_double() const
Definition: variant.h:106
static Variant get_value(const NotePtr note, Property prop)
Definition: midi_model.cc:168
Variant eval(const Context &context) const
Definition: transform.cc:44
Definition: amp.h:29
size_t n_notes
Total number of notes to process.
Definition: transform.h:65
std::string name() const
Definition: transform.h:138
std::stack< Variant > stack
The stack of everything.
Definition: transform.h:63
size_t index
Index of current note.
Definition: transform.h:64
Signed 32-bit int.
Definition: variant.h:45
NotePtr prev_note
Previous note.
Definition: transform.h:66
Type type() const
Definition: variant.h:177
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
Command * operator()(boost::shared_ptr< ARDOUR::MidiModel > model, Evoral::Beats position, std::vector< Notes > &seqs)
Definition: transform.cc:123
NotePtr this_note
Current note.
Definition: transform.h:67
Transform(const Program &prog)
Definition: transform.cc:27
std::list< Operation > ops
List of operations.
Definition: transform.h:129