2 Copyright (C) 2014 Paul Davis
3 Author: David Robillard
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.
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.
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.
22 #include "ardour/transform.h"
23 #include "ardour/midi_model.h"
27 Transform::Transform(const Program& prog)
32 Transform::Context::pop()
38 const Variant top = stack.top();
44 Transform::Value::eval(const Context& ctx) const
50 return MidiModel::NoteDiffCommand::get_value(ctx.this_note, prop);
55 return MidiModel::NoteDiffCommand::get_value(ctx.prev_note, prop);
57 return Variant(Variant::INT, ctx.index);
59 return Variant(Variant::INT, ctx.n_notes);
63 return Variant(g_random_double());
70 Transform::Operation::eval(Context& ctx) const
73 const Variant a = arg.eval(ctx);
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. */
83 // Pop operands off the stack
84 const Variant rhs = ctx.pop();
85 const Variant lhs = ctx.pop();
87 // Stack underflow (probably previous note reference), do nothing
91 // We can get away with just using double math and converting twice
92 double value = lhs.to_double();
95 value += rhs.to_double();
98 value -= rhs.to_double();
101 value *= rhs.to_double();
104 if (rhs.to_double() == 0.0) {
105 return; // Program will fail safely
107 value /= rhs.to_double();
110 if (rhs.to_double() == 0.0) {
111 return; // Program will fail safely
113 value = fmod(value, rhs.to_double());
118 // Push result on to the stack
119 ctx.stack.push(Variant(lhs.type(), value));
123 Transform::operator()(boost::shared_ptr<MidiModel> model,
124 Evoral::Beats position,
125 std::vector<Notes>& seqs)
127 typedef MidiModel::NoteDiffCommand Command;
129 Command* cmd = new Command(model, name());
131 for (std::vector<Notes>::iterator s = seqs.begin(); s != seqs.end(); ++s) {
133 ctx.n_notes = (*s).size();
134 for (Notes::const_iterator i = (*s).begin(); i != (*s).end(); ++i) {
135 const NotePtr note = *i;
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();
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),
157 cmd->change(note, _prog.prop, result);
159 // else error or reference to note before the first, skip
162 ctx.prev_note = note;
170 } // namespace ARDOUR