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.
20 #ifndef __ardour_transform_h__
21 #define __ardour_transform_h__
26 #include "ardour/libardour_visibility.h"
27 #include "ardour/midi_model.h"
28 #include "ardour/midi_operator.h"
29 #include "ardour/types.h"
30 #include "ardour/variant.h"
34 /** Transform notes with a user-defined transformation.
36 * This is essentially an interpreter for a simple concatenative note
37 * transformation language (as an AST only, no source code). A "program"
38 * calculates a note property value from operations on literal values, and/or
39 * values from the current or previous note in the sequence. This allows
40 * simple things like "set all notes' velocity to 64" or transitions over time
41 * like "set velocity to the previous note's velocity + 10".
43 * The language is forth-like: everything is on a stack, operations pop their
44 * arguments from the stack and push their result back on to it.
46 * This is a sweet spot between simplicity and power, it should be simple to
47 * use this (with perhaps some minor extensions) to do most "linear-ish"
48 * transformations, though it could be extended to have random access
49 * and more special values as the need arises.
51 class LIBARDOUR_API Transform : public MidiOperator {
53 typedef Evoral::Sequence<Temporal::Beats>::NotePtr NotePtr;
54 typedef Evoral::Sequence<Temporal::Beats>::Notes Notes;
55 typedef ARDOUR::MidiModel::NoteDiffCommand::Property Property;
57 /** Context while iterating over notes during transformation. */
59 Context() : index(0) {}
63 std::stack<Variant> stack; ///< The stack of everything
64 size_t index; ///< Index of current note
65 size_t n_notes; ///< Total number of notes to process
66 NotePtr prev_note; ///< Previous note
67 NotePtr this_note; ///< Current note
70 /** Value in a transformation expression. */
72 /** Value source. Some of these would be better modeled as properties,
73 like note.index or sequence.size, but until the sequence stuff is
74 more fundamentally property based, we special-case them here. */
77 THIS_NOTE, ///< Value from this note
78 PREV_NOTE, ///< Value from the previous note
79 INDEX, ///< Index of the current note
80 N_NOTES, ///< Total number of notes to process
81 LITERAL, ///< Given literal value
82 RANDOM ///< Random normal
85 Value() : source(NOWHERE) {}
86 Value(Source s) : source(s) {}
87 Value(const Variant& v) : source(LITERAL), value(v) {}
88 Value(double v) : source(LITERAL), value(Variant(v)) {}
90 /** Calculate and return value. */
91 Variant eval(const Context& context) const;
93 Source source; ///< Source of value
94 Variant value; ///< Value for LITERAL
95 Property prop; ///< Property for all other sources
98 /** An operation to transform the running result.
100 * All operations except PUSH take their arguments from the stack, and put
101 * the result back on the stack.
105 PUSH, ///< Push argument to the stack
106 ADD, ///< Add top two values
107 SUB, ///< Subtract top from second-top
108 MULT, ///< Multiply top two values
109 DIV, ///< Divide second-top by top
110 MOD ///< Modulus (division remainder)
113 Operation(Operator o, const Value& a=Value()) : op(o), arg(a) {}
115 /** Apply operation. */
116 void eval(Context& context) const;
122 /** A transformation program.
124 * A program is a list of operations to calculate the target property's
125 * final value. The first operation must be a PUSH to seed the stack.
128 Property prop; ///< Property to calculate
129 std::list<Operation> ops; ///< List of operations
132 Transform(const Program& prog);
134 Command* operator()(boost::shared_ptr<ARDOUR::MidiModel> model,
135 Temporal::Beats position,
136 std::vector<Notes>& seqs);
138 std::string name() const { return std::string ("transform"); }
146 #endif /* __ardour_transform_h__ */