summaryrefslogtreecommitdiffstats
path: root/src/base/Quantizer.h
blob: 035299c79dc343c7af4c7d5a15dec3f864a4f0ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
// -*- c-basic-offset: 4 -*-

/*
    Rosegarden
    A sequencer and musical notation editor.

    This program is Copyright 2000-2008
        Guillaume Laurent   <[email protected]>,
        Chris Cannam        <[email protected]>,
        Richard Bown        <[email protected]>

    The moral right of the authors to claim authorship of this work
    has been asserted.

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#ifndef TQUANTIZER_H
#define TQUANTIZER_H

#include "Segment.h"
#include "Event.h"
#include "NotationTypes.h"
#include "FastVector.h"
#include <string>

namespace Rosegarden {

class EventSelection;

/**
   The Quantizer class rounds the starting times and durations of note
   and rest events according to one of a set of possible criteria.
*/

class Quantizer
{
    // define the Quantizer API

public:
    virtual ~Quantizer();

    /**
     * Quantize a Segment.
     */
    void quantize(Segment *) const;

    /**
     * Quantize a section of a Segment.
     */
    void quantize(Segment *,
                  Segment::iterator from,
                  Segment::iterator to) const;

    /**
     * Quantize an EventSelection.
     */
    void quantize(EventSelection *);

    /**
     * Quantize a section of a Segment, and force the quantized
     * results into the formal absolute time and duration of
     * the events.  This is a destructive operation that should
     * not be carried out except on a user's explicit request.
     * (If target is RawEventData, this will do nothing besides
     * quantize.  In this case, but no other, unquantize will
     * still work afterwards.)
     */
    void fixQuantizedValues(Segment *,
                            Segment::iterator from,
                            Segment::iterator to) const;

    /**
     * Return the quantized duration of the event if it has been
     * quantized -- otherwise just return the unquantized duration.
     * Do not modify the event.
     */
    virtual timeT getQuantizedDuration(const Event *e) const;

    /**
     * Return the quantized absolute time of the event if it has been
     * quantized -- otherwise just return the unquantized time.  Do
     * not modify the event.
     */
    virtual timeT getQuantizedAbsoluteTime(const Event *e) const;

    /**
     * Return the unquantized absolute time of the event --
     * the absolute time that would be restored by a call to
     * unquantize.
     */
    virtual timeT getUnquantizedAbsoluteTime(Event *e) const;

    /**
     * Return the unquantized absolute time of the event --
     * the absolute time that would be restored by a call to
     * unquantize.
     */
    virtual timeT getUnquantizedDuration(Event *e) const;

    /**
     * Unquantize all events in the given range, for this
     * quantizer.  Properties set by other quantizers with
     * different propertyNamePrefix values will remain.
     */
    void unquantize(Segment *,
                    Segment::iterator from, Segment::iterator to) const;

    /**
     * Unquantize a selection of Events
     */
    void unquantize(EventSelection *) const;

    static const std::string RawEventData;
    static const std::string DefaultTarget;
    static const std::string GlobalSource;
    static const std::string NotationPrefix;

protected:
    /**
     * \arg source, target : Description of where to find the
     * times to be quantized, and where to put the quantized results.
     * 
     * These may be strings, specifying a prefix for the names
     * of properties to contain the timings, or may be the special
     * value RawEventData in which case the event's absolute time
     * and duration will be used instead of properties.
     * 
     * If source specifies a property prefix for properties that are
     * found not to exist, they will be pre-filled from the original
     * timings in the target values before being quantized and then
     * set back into the target.  (This permits a quantizer to write
     * directly into the Event's absolute time and duration without
     * losing the original values, because they are backed up
     * automatically into the source properties.)
     * 
     * Note that because it's impossible to modify the duration or
     * absolute time of an event after construction, if target is
     * RawEventData the quantizer must re-construct each event in
     * order to adjust its timings.  This operation (deliberately)
     * loses any non-persistent properties in the events.  This
     * does not happen if target is a property prefix.
     *
     *   Examples:
     *
     *   -- if source == RawEventData and target == "MyPrefix",
     *   values will be read from the event's absolute time and
     *   duration, quantized, and written into MyPrefixAbsoluteTime
     *   and MyPrefixDuration properties on the event.  A call to
     *   unquantize will simply delete these properties.
     *
     *   -- if source == "MyPrefix" and target == RawEventData,
     *   the MyPrefixAbsoluteTime and MyPrefixDuration will be
     *   populated if necessary from the event's absolute time and
     *   duration, and then quantized and written back into the
     *   event's values.  A call to unquantize will write the
     *   MyPrefix-property timings back into the event's values,
     *   and delete the MyPrefix properties.
     *
     *   -- if source == "YourPrefix" and target == "MyPrefix",
     *   values will be read from YourPrefixAbsoluteTime and
     *   YourPrefixDuration, quantized, and written into the
     *   MyPrefix-properties.  This may be useful for piggybacking
     *   onto another quantizer's output.
     *
     *   -- if source == RawEventData and target == RawEventData,
     *   values will be read from the event's absolute time and
     *   duration, quantized, and written back to these values.
     */
    Quantizer(std::string source, std::string target);

    /**
     * If only target is supplied, source is deduced appropriately
     * as GlobalSource if target == RawEventData and RawEventData
     * otherwise.
     */
    Quantizer(std::string target);

    /**
     * To implement a subclass of Quantizer, you should
     * override either quantizeSingle (if your quantizer is simple
     * enough only to have to look at a single event at a time) or
     * quantizeRange.  The default implementation of quantizeRange
     * simply calls quantizeSingle on each non-rest event in turn.
     * The default implementation of quantizeSingle, as you see,
     * does nothing.
     * 
     * Note that implementations of these methods should call
     * getFromSource and setToTarget to get and set the unquantized
     * and quantized data; they should not query the event properties
     * or timings directly.
     *
     * NOTE: It is vital that ordering is maintained after
     * quantization.  That is, an event whose absolute time quantizes
     * to a time t must appear in the original segment before all
     * events whose times quantize to greater than t.  This means you
     * must quantize the absolute times of non-note events as well as
     * notes.  You don't need to worry about quantizing rests,
     * however; they're only used for notation and will be
     * automatically recalculated if the notation quantization values
     * are seen to change.
     */
    virtual void quantizeSingle(Segment *,
                                Segment::iterator) const { }

    /**
     * See note for quantizeSingle.
     */
    virtual void quantizeRange(Segment *,
                               Segment::iterator,
                               Segment::iterator) const;

    std::string m_source;
    std::string m_target;
    mutable std::pair<timeT, timeT> m_normalizeRegion;

    enum ValueType { AbsoluteTimeValue = 0, DurationValue = 1 };

    PropertyName m_sourceProperties[2];
    PropertyName m_targetProperties[2];

public: // should be protected, but gcc-2.95 doesn't like allowing NotationQuantizer::m_impl to access them
    timeT getFromSource(Event *, ValueType) const;
    timeT getFromTarget(Event *, ValueType) const;
    void setToTarget(Segment *, Segment::iterator, timeT t, timeT d) const;
    mutable FastVector<Event *> m_toInsert;

protected:
    void removeProperties(Event *) const;
    void removeTargetProperties(Event *) const;
    void makePropertyNames();

    void insertNewEvents(Segment *) const;

private: // not provided
    Quantizer(const Quantizer &);
    Quantizer &operator=(const Quantizer &);
    bool operator==(const Quantizer &) const;
    bool operator!=(const Quantizer & c) const;
};


}

#endif