const bool METHOD() const makes no sense
[ardour.git] / libs / ardour / ardour / transform.h
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 #ifndef __ardour_transform_h__
21 #define __ardour_transform_h__
22
23 #include <stack>
24 #include <string>
25
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"
31
32 namespace ARDOUR {
33
34 /** Transform notes with a user-defined transformation.
35  *
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".
42  *
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.
45  *
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.
50  */
51 class LIBARDOUR_API Transform : public MidiOperator {
52 public:
53         typedef Evoral::Sequence<Evoral::Beats>::NotePtr     NotePtr;
54         typedef Evoral::Sequence<Evoral::Beats>::Notes       Notes;
55         typedef ARDOUR::MidiModel::NoteDiffCommand::Property Property;
56
57         /** Context while iterating over notes during transformation. */
58         struct Context {
59                 Context() : index(0) {}
60
61                 Variant pop();
62
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
68         };
69
70         /** Value in a transformation expression. */
71         struct Value {
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. */
75                 enum Source {
76                         NOWHERE,    ///< Null
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
83                 };
84
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)) {}
89
90                 /** Calculate and return value. */
91                 Variant eval(const Context& context) const;
92
93                 Source   source;  ///< Source of value
94                 Variant  value;   ///< Value for LITERAL
95                 Property prop;    ///< Property for all other sources
96         };
97
98         /** An operation to transform the running result.
99          *
100          * All operations except PUSH take their arguments from the stack, and put
101          * the result back on the stack.
102          */
103         struct Operation {
104                 enum Operator {
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)
111                 };
112
113                 Operation(Operator o, const Value& a=Value()) : op(o), arg(a) {}
114
115                 /** Apply operation. */
116                 void eval(Context& context) const;
117
118                 Operator op;
119                 Value    arg;
120         };
121
122         /** A transformation program.
123          *
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.
126          */
127         struct Program {
128                 Property             prop;  ///< Property to calculate
129                 std::list<Operation> ops;   ///< List of operations
130         };
131
132         Transform(const Program& prog);
133
134         Command* operator()(boost::shared_ptr<ARDOUR::MidiModel> model,
135                             Evoral::Beats                        position,
136                             std::vector<Notes>&                  seqs);
137
138         std::string name() const { return std::string ("transform"); }
139
140 private:
141         const Program _prog;
142 };
143
144 } /* namespace */
145
146 #endif /* __ardour_transform_h__ */