~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to libs/ardour/source.cc

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2000 Paul Davis
 
3
 
 
4
    This program is free software; you can redistribute it and/or modify
 
5
    it under the terms of the GNU General Public License as published by
 
6
    the Free Software Foundation; either version 2 of the License, or
 
7
    (at your option) any later version.
 
8
 
 
9
    This program is distributed in the hope that it will be useful,
 
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
    GNU General Public License for more details.
 
13
 
 
14
    You should have received a copy of the GNU General Public License
 
15
    along with this program; if not, write to the Free Software
 
16
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
 
 
18
*/
 
19
 
 
20
#include <sys/stat.h>
 
21
#include <unistd.h>
 
22
#include <fcntl.h>
 
23
#include <poll.h>
 
24
#include <float.h>
 
25
#include <cerrno>
 
26
#include <ctime>
 
27
#include <cmath>
 
28
#include <iomanip>
 
29
#include <algorithm>
 
30
#include <fstream>
 
31
 
 
32
#include <glibmm/threads.h>
 
33
#include <glibmm/miscutils.h>
 
34
#include <glibmm/fileutils.h>
 
35
#include "pbd/xml++.h"
 
36
#include "pbd/pthread_utils.h"
 
37
#include "pbd/enumwriter.h"
 
38
 
 
39
#include "ardour/debug.h"
 
40
#include "ardour/session.h"
 
41
#include "ardour/source.h"
 
42
#include "ardour/transient_detector.h"
 
43
 
 
44
#include "i18n.h"
 
45
 
 
46
using namespace std;
 
47
using namespace ARDOUR;
 
48
using namespace PBD;
 
49
 
 
50
Source::Source (Session& s, DataType type, const string& name, Flag flags)
 
51
        : SessionObject(s, name)
 
52
        , _type(type)
 
53
        , _flags(flags)
 
54
        , _timeline_position(0)
 
55
        , _use_count (0)
 
56
        , _level (0)
 
57
{
 
58
        _analysed = false;
 
59
        _timestamp = 0;
 
60
        fix_writable_flags ();
 
61
}
 
62
 
 
63
Source::Source (Session& s, const XMLNode& node)
 
64
        : SessionObject(s, "unnamed source")
 
65
        , _type(DataType::AUDIO)
 
66
        , _flags (Flag (Writable|CanRename))
 
67
        , _timeline_position(0)
 
68
        , _use_count (0)
 
69
        , _level (0)
 
70
{
 
71
        _timestamp = 0;
 
72
        _analysed = false;
 
73
 
 
74
        if (set_state (node, Stateful::loading_state_version) || _type == DataType::NIL) {
 
75
                throw failed_constructor();
 
76
        }
 
77
 
 
78
        fix_writable_flags ();
 
79
}
 
80
 
 
81
Source::~Source ()
 
82
{
 
83
        DEBUG_TRACE (DEBUG::Destruction, string_compose ("Source %1 destructor %2\n", _name, this));
 
84
}
 
85
 
 
86
void
 
87
Source::fix_writable_flags ()
 
88
{
 
89
        if (!_session.writable()) {
 
90
                _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
 
91
        }
 
92
}
 
93
 
 
94
XMLNode&
 
95
Source::get_state ()
 
96
{
 
97
        XMLNode *node = new XMLNode ("Source");
 
98
        char buf[64];
 
99
 
 
100
        node->add_property ("name", name());
 
101
        node->add_property ("type", _type.to_string());
 
102
        node->add_property (X_("flags"), enum_2_string (_flags));
 
103
        id().print (buf, sizeof (buf));
 
104
        node->add_property ("id", buf);
 
105
 
 
106
        if (_timestamp != 0) {
 
107
                snprintf (buf, sizeof (buf), "%ld", _timestamp);
 
108
                node->add_property ("timestamp", buf);
 
109
        }
 
110
 
 
111
        return *node;
 
112
}
 
113
 
 
114
int
 
115
Source::set_state (const XMLNode& node, int version)
 
116
{
 
117
        const XMLProperty* prop;
 
118
 
 
119
        if ((prop = node.property ("name")) != 0) {
 
120
                _name = prop->value();
 
121
        } else {
 
122
                return -1;
 
123
        }
 
124
 
 
125
        if (!set_id (node)) {
 
126
                return -1;
 
127
        }
 
128
 
 
129
        if ((prop = node.property ("type")) != 0) {
 
130
                _type = DataType(prop->value());
 
131
        }
 
132
 
 
133
        if ((prop = node.property ("timestamp")) != 0) {
 
134
                sscanf (prop->value().c_str(), "%ld", &_timestamp);
 
135
        }
 
136
 
 
137
        if ((prop = node.property (X_("flags"))) != 0) {
 
138
                _flags = Flag (string_2_enum (prop->value(), _flags));
 
139
        } else {
 
140
                _flags = Flag (0);
 
141
 
 
142
        }
 
143
 
 
144
        /* old style, from the period when we had DestructiveFileSource */
 
145
        if ((prop = node.property (X_("destructive"))) != 0) {
 
146
                _flags = Flag (_flags | Destructive);
 
147
        }
 
148
 
 
149
        if (version < 3000) {
 
150
                /* a source with an XML node must necessarily already exist,
 
151
                   and therefore cannot be removable/writable etc. etc.; 2.X
 
152
                   sometimes marks sources as removable which shouldn't be.
 
153
                */
 
154
                if (!(_flags & Destructive)) {
 
155
                        _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
 
156
                }
 
157
        }
 
158
 
 
159
        return 0;
 
160
}
 
161
 
 
162
bool
 
163
Source::has_been_analysed() const
 
164
{
 
165
        Glib::Threads::Mutex::Lock lm (_analysis_lock);
 
166
        return _analysed;
 
167
}
 
168
 
 
169
void
 
170
Source::set_been_analysed (bool yn)
 
171
{
 
172
        {
 
173
                Glib::Threads::Mutex::Lock lm (_analysis_lock);
 
174
                _analysed = yn;
 
175
        }
 
176
 
 
177
        if (yn) {
 
178
                load_transients (get_transients_path());
 
179
                AnalysisChanged(); // EMIT SIGNAL
 
180
        }
 
181
}
 
182
 
 
183
int
 
184
Source::load_transients (const string& path)
 
185
{
 
186
        ifstream file (path.c_str());
 
187
 
 
188
        if (!file) {
 
189
                return -1;
 
190
        }
 
191
 
 
192
        transients.clear ();
 
193
 
 
194
        stringstream strstr;
 
195
        double val;
 
196
 
 
197
        while (file.good()) {
 
198
                file >> val;
 
199
 
 
200
                if (!file.fail()) {
 
201
                        framepos_t frame = (framepos_t) floor (val * _session.frame_rate());
 
202
                        transients.push_back (frame);
 
203
                }
 
204
        }
 
205
 
 
206
        return 0;
 
207
}
 
208
 
 
209
string
 
210
Source::get_transients_path () const
 
211
{
 
212
        vector<string> parts;
 
213
        string s;
 
214
 
 
215
        /* old sessions may not have the analysis directory */
 
216
 
 
217
        _session.ensure_subdirs ();
 
218
 
 
219
        s = _session.analysis_dir ();
 
220
        parts.push_back (s);
 
221
 
 
222
        s = id().to_s();
 
223
        s += '.';
 
224
        s += TransientDetector::operational_identifier();
 
225
        parts.push_back (s);
 
226
 
 
227
        return Glib::build_filename (parts);
 
228
}
 
229
 
 
230
bool
 
231
Source::check_for_analysis_data_on_disk ()
 
232
{
 
233
        /* looks to see if the analysis files for this source are on disk.
 
234
           if so, mark us already analysed.
 
235
        */
 
236
 
 
237
        string path = get_transients_path ();
 
238
        bool ok = true;
 
239
 
 
240
        if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
 
241
                ok = false;
 
242
        }
 
243
 
 
244
        // XXX add other tests here as appropriate
 
245
 
 
246
        set_been_analysed (ok);
 
247
        return ok;
 
248
}
 
249
 
 
250
void
 
251
Source::mark_for_remove ()
 
252
{
 
253
        // This operation is not allowed for sources for destructive tracks or out-of-session files.
 
254
 
 
255
        /* XXX need a way to detect _within_session() condition here - move it from FileSource?
 
256
         */
 
257
 
 
258
        if ((_flags & Destructive)) {
 
259
                return;
 
260
        }
 
261
 
 
262
        _flags = Flag (_flags | Removable | RemoveAtDestroy);
 
263
}
 
264
 
 
265
void
 
266
Source::set_timeline_position (framepos_t pos)
 
267
{
 
268
        _timeline_position = pos;
 
269
}
 
270
 
 
271
void
 
272
Source::set_allow_remove_if_empty (bool yn)
 
273
{
 
274
        if (!writable()) {
 
275
                return;
 
276
        }
 
277
 
 
278
        if (yn) {
 
279
                _flags = Flag (_flags | RemovableIfEmpty);
 
280
        } else {
 
281
                _flags = Flag (_flags & ~RemovableIfEmpty);
 
282
        }
 
283
}
 
284
 
 
285
void
 
286
Source::inc_use_count ()
 
287
{
 
288
        g_atomic_int_inc (&_use_count);
 
289
}
 
290
 
 
291
void
 
292
Source::dec_use_count ()
 
293
{
 
294
#ifndef NDEBUG
 
295
        gint oldval = g_atomic_int_add (&_use_count, -1);
 
296
        if (oldval <= 0) {
 
297
                cerr << "Bad use dec for " << name() << endl;
 
298
                abort ();
 
299
        }
 
300
        assert (oldval > 0);
 
301
#else
 
302
        g_atomic_int_add (&_use_count, -1);
 
303
#endif
 
304
}
 
305
 
 
306
bool
 
307
Source::writable () const
 
308
{
 
309
        return (_flags & Writable) && _session.writable();
 
310
}
 
311