start removal of NoteFixer code
[ardour.git] / libs / ardour / export_filename.cc
1 /*
2  * Copyright (C) 2008-2016 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2009-2012 David Robillard <d@drobilla.net>
4  * Copyright (C) 2011-2013 Sakari Bergen <sakari.bergen@beatwaves.net>
5  * Copyright (C) 2012-2016 Tim Mayberry <mojofunk@gmail.com>
6  * Copyright (C) 2014 Nick Mainsbridge <mainsbridge@gmail.com>
7  * Copyright (C) 2015-2018 Robin Gareus <robin@gareus.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include <string>
25
26 #include <glibmm/miscutils.h>
27 #include <glibmm/fileutils.h>
28
29 #include "pbd/xml++.h"
30 #include "pbd/string_convert.h"
31 #include "pbd/enumwriter.h"
32 #include "pbd/localtime_r.h"
33
34 #include "ardour/libardour_visibility.h"
35 #include "ardour/session.h"
36 #include "ardour/session_directory.h"
37 #include "ardour/export_filename.h"
38 #include "ardour/export_format_specification.h"
39 #include "ardour/export_channel_configuration.h"
40 #include "ardour/export_timespan.h"
41 #include "ardour/utils.h"
42
43 #include "pbd/i18n.h"
44
45 using namespace PBD;
46 using namespace Glib;
47 using std::string;
48
49 namespace ARDOUR
50 {
51
52 ExportFilename::ExportFilename (Session & session) :
53   include_label (false),
54   include_session (false),
55   use_session_snapshot_name (false),
56   include_revision (false),
57   include_channel_config (false),
58   include_format_name (false),
59   include_channel (false),
60   include_timespan (true), // Include timespan name always
61   include_time (false),
62   include_date (false),
63   session (session),
64   revision (1),
65   date_format (D_None),
66   time_format (T_None)
67 {
68         time_t rawtime;
69         std::time (&rawtime);
70         localtime_r (&rawtime, &time_struct);
71
72         folder = session.session_directory().export_path();
73
74         XMLNode * extra_node = session.extra_xml ("ExportFilename");
75         /* Legacy sessions used Session instant.xml for this */
76         if (!extra_node) {
77                 session.instant_xml ("ExportFilename");
78         }
79
80         if (extra_node) {
81                 set_state (*extra_node);
82         }
83 }
84
85 XMLNode &
86 ExportFilename::get_state ()
87 {
88         XMLNode * node = new XMLNode ("ExportFilename");
89         XMLNode * child;
90
91         FieldPair dir = analyse_folder();
92         child = node->add_child ("Folder");
93         child->set_property ("relative", dir.first);
94         child->set_property ("path", dir.second);
95
96         add_field (node, "label", include_label, label);
97         add_field (node, "session", include_session);
98         add_field (node, "snapshot", use_session_snapshot_name);
99         add_field (node, "timespan", include_timespan);
100         add_field (node, "revision", include_revision);
101         add_field (node, "time", include_time, enum_2_string (time_format));
102         add_field (node, "date", include_date, enum_2_string (date_format));
103
104         XMLNode * extra_node = new XMLNode ("ExportRevision");
105         extra_node->set_property ("revision", revision);
106         session.add_extra_xml (*extra_node);
107
108         return *node;
109 }
110
111 int
112 ExportFilename::set_state (const XMLNode & node)
113 {
114         XMLNode * child;
115         FieldPair pair;
116
117         child = node.child ("Folder");
118         if (!child) { return -1; }
119
120         folder = "";
121
122         bool is_relative;
123         if (child->get_property ("relative", is_relative) && is_relative) {
124                 folder = session.session_directory ().root_path ();
125         }
126
127         std::string tmp;
128         if (child->get_property ("path", tmp)) {
129                 tmp = Glib::build_filename (folder, tmp);
130                 if (!Glib::file_test (tmp, Glib::FILE_TEST_EXISTS)) {
131                         warning << string_compose (_("Existing export folder for this session (%1) does not exist - ignored"), tmp) << endmsg;
132                 } else {
133                         folder = tmp;
134                 }
135         }
136
137         if (folder.empty() || !Glib::file_test (folder, FileTest (FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
138                 folder = session.session_directory().export_path();
139         }
140
141         pair = get_field (node, "label");
142         include_label = pair.first;
143         label = pair.second;
144
145         pair = get_field (node, "session");
146         include_session = pair.first;
147
148         pair = get_field (node, "snapshot");
149         use_session_snapshot_name = pair.first;
150
151         pair = get_field (node, "timespan");
152         include_timespan = pair.first;
153
154         pair = get_field (node, "revision");
155         include_revision = pair.first;
156
157         pair = get_field (node, "time");
158         include_time = pair.first;
159         time_format = (TimeFormat) string_2_enum (pair.second, time_format);
160
161         pair = get_field (node, "date");
162         include_date = pair.first;
163         date_format = (DateFormat) string_2_enum (pair.second, date_format);
164
165         XMLNode * extra_node = session.extra_xml ("ExportRevision");
166         /* Legacy sessions used Session instant.xml for this */
167         if (!extra_node) {
168                 extra_node = session.instant_xml ("ExportRevision");
169         }
170
171         if (extra_node) {
172                 extra_node->get_property ("revision", revision);
173         }
174
175         return 0;
176 }
177
178 string
179 ExportFilename::get_path (ExportFormatSpecPtr format) const
180 {
181         string path;
182         bool filename_empty = true;
183         bool with_timespan = include_timespan;
184
185         if (!include_session
186                         && !include_label
187                         && !include_revision
188                         && !include_timespan
189                         && !include_channel_config
190                         && !include_channel
191                         && !include_date) {
192                 with_timespan = true;
193         }
194
195         if (include_session) {
196                 path += filename_empty ? "" : "_";
197                 if (use_session_snapshot_name) {
198                         path += session.snap_name();
199                 } else {
200                         path += session.name();
201                 }
202                 filename_empty = false;
203         }
204
205         if (include_label) {
206                 path += filename_empty ? "" : "_";
207                 path += label;
208                 filename_empty = false;
209         }
210
211         if (include_revision) {
212                 path += filename_empty ? "" : "_";
213                 path += "r";
214                 path += to_string (revision);
215                 filename_empty = false;
216         }
217
218         if (with_timespan && timespan) {
219                 path += filename_empty ? "" : "_";
220                 path += timespan->name();
221                 filename_empty = false;
222         }
223
224         if (include_channel_config && channel_config) {
225                 path += filename_empty ? "" : "_";
226                 path += channel_config->name();
227                 filename_empty = false;
228         }
229
230         if (include_channel) {
231                 path += filename_empty ? "" : "_";
232                 path += "channel";
233                 path += to_string (channel);
234                 filename_empty = false;
235         }
236
237         if (include_date) {
238                 path += filename_empty ? "" : "_";
239                 path += get_date_format_str (date_format);
240                 filename_empty = false;
241         }
242
243         if (include_time) {
244                 path += filename_empty ? "" : "_";
245                 path += get_time_format_str (time_format);
246                 filename_empty = false;
247         }
248
249         if (include_format_name && format) {
250                 path += filename_empty ? "" : "_";
251                 path += format->name();
252                 filename_empty = false;
253         }
254
255         if (path.empty ()) {
256                 path = "export";
257         }
258
259         if (format) {
260                 path += ".";
261                 path += format->extension ();
262         }
263
264         path = legalize_for_universal_path (path);
265
266         return Glib::build_filename (folder, path);
267 }
268
269 string
270 ExportFilename::get_time_format_str (TimeFormat format) const
271 {
272         switch ( format ) {
273           case T_None:
274                 return _("No Time");
275
276           case T_NoDelim:
277                 return get_formatted_time ("%H%M");
278
279           case T_Delim:
280                 return get_formatted_time ("%H.%M");
281
282           default:
283                 return _("Invalid time format");
284         }
285 }
286
287 string
288 ExportFilename::get_date_format_str (DateFormat format) const
289 {
290         switch (format) {
291           case D_None:
292                 return _("No Date");
293
294           case D_BE:
295                 return get_formatted_time ("%Y%m%d");
296
297           case D_ISO:
298                 return get_formatted_time ("%Y-%m-%d");
299
300           case D_BEShortY:
301                 return get_formatted_time ("%y%m%d");
302
303           case D_ISOShortY:
304                 return get_formatted_time ("%y-%m-%d");
305
306           default:
307                 return _("Invalid date format");
308         }
309 }
310
311 void
312 ExportFilename::set_time_format (TimeFormat format)
313 {
314         time_format = format;
315
316         if (format == T_None) {
317                 include_time = false;
318         } else {
319                 include_time = true;
320         }
321 }
322
323 void
324 ExportFilename::set_date_format (DateFormat format)
325 {
326         date_format = format;
327
328         if (format == D_None) {
329                 include_date = false;
330         } else {
331                 include_date = true;
332         }
333 }
334
335 void
336 ExportFilename::set_label (string value)
337 {
338         label = value;
339         include_label = !value.compare ("");
340 }
341
342 bool
343 ExportFilename::set_folder (string path)
344 {
345         // TODO check folder existence
346         folder = path;
347         return true;
348 }
349
350 string
351 ExportFilename::get_formatted_time (string const & format) const
352 {
353         char buffer [80];
354         strftime (buffer, 80, format.c_str(), &time_struct);
355
356         string return_value (buffer);
357         return return_value;
358 }
359
360 void
361 ExportFilename::add_field (XMLNode * node, string const & name, bool enabled, string const & value)
362 {
363         XMLNode * child = node->add_child ("Field");
364
365         if (!child) {
366                 std::cerr << "Error adding a field to ExportFilename XML-tree" << std::endl;
367                 return;
368         }
369
370         child->set_property ("name", name);
371         child->set_property ("enabled", enabled);
372         if (!value.empty()) {
373                 child->set_property ("value", value);
374         }
375 }
376
377 ExportFilename::FieldPair
378 ExportFilename::get_field (XMLNode const & node, string const & name)
379 {
380         FieldPair pair;
381         pair.first = false;
382
383         XMLNodeList children = node.children();
384
385         for (XMLNodeList::iterator it = children.begin(); it != children.end(); ++it) {
386                 std::string str;
387                 if ((*it)->get_property ("name", str) && name == str) {
388
389                         (*it)->get_property ("enabled", pair.first);
390                         (*it)->get_property ("value", pair.second);
391
392                         return pair;
393                 }
394         }
395
396         return pair;
397 }
398
399 ExportFilename::FieldPair
400 ExportFilename::analyse_folder ()
401 {
402         FieldPair pair;
403
404         string session_dir = session.session_directory().root_path();
405         string::size_type session_dir_len = session_dir.length();
406
407         string folder_beginning = folder.substr (0, session_dir_len);
408
409         if (!folder_beginning.compare (session_dir)) {
410                 pair.first = true;
411                 pair.second = folder.substr (session_dir_len);
412         } else {
413                 pair.first = false;
414                 pair.second = folder;
415         }
416
417         return pair;
418 }
419
420 } // namespace ARDOUR