1 /*
2  * Copyright (C) 2018-2021 Alexandros Theodotou <alex at zrythm dot org>
3  *
4  * This file is part of Zrythm
5  *
6  * Zrythm is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Zrythm is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 /**
21  * \file
22  *
23  * A project (or song), containing all the project
24  * data as opposed to zrythm_app.h which manages
25  * global things like plugin descriptors and global
26  * settings.
27  */
28 
29 #ifndef __PROJECT_H__
30 #define __PROJECT_H__
31 
32 #include "actions/undo_manager.h"
33 #include "audio/engine.h"
34 #include "audio/midi_mapping.h"
35 #include "audio/midi_note.h"
36 #include "audio/port.h"
37 #include "audio/port_connections_manager.h"
38 #include "audio/quantize_options.h"
39 #include "audio/region.h"
40 #include "audio/region_link_group_manager.h"
41 #include "audio/tracklist.h"
42 #include "gui/backend/clip_editor.h"
43 #include "gui/backend/audio_selections.h"
44 #include "gui/backend/automation_selections.h"
45 #include "gui/backend/chord_selections.h"
46 #include "gui/backend/midi_arranger_selections.h"
47 #include "gui/backend/mixer_selections.h"
48 #include "gui/backend/timeline.h"
49 #include "gui/backend/timeline_selections.h"
50 #include "gui/backend/tool.h"
51 #include "plugins/plugin.h"
52 #include "zrythm.h"
53 
54 #include "ext/zix/zix/sem.h"
55 
56 #include <gtk/gtk.h>
57 
58 typedef struct Timeline Timeline;
59 typedef struct Transport Transport;
60 typedef struct Tracklist Tracklist;
61 typedef struct TracklistSelections
62   TracklistSelections;
63 
64 /**
65  * @addtogroup project Project
66  *
67  * @{
68  */
69 
70 #define PROJECT_SCHEMA_VERSION 1
71 
72 #define PROJECT                 ZRYTHM->project
73 #define DEFAULT_PROJECT_NAME    "Untitled Project"
74 #define PROJECT_FILE            "project.zpj"
75 #define PROJECT_BACKUPS_DIR     "backups"
76 #define PROJECT_PLUGINS_DIR     "plugins"
77 #define PROJECT_PLUGIN_STATES_DIR "states"
78 #define PROJECT_PLUGIN_EXT_COPIES_DIR "ext_file_copies"
79 #define PROJECT_PLUGIN_EXT_LINKS_DIR "ext_file_links"
80 #define PROJECT_EXPORTS_DIR     "exports"
81 #define PROJECT_STEMS_DIR       "stems"
82 #define PROJECT_POOL_DIR        "pool"
83 
84 typedef enum ProjectPath
85 {
86   PROJECT_PATH_PROJECT_FILE,
87   PROJECT_PATH_BACKUPS,
88 
89   /** Plugins path. */
90   PROJECT_PATH_PLUGINS,
91 
92   /** Path for state .ttl files. */
93   PROJECT_PATH_PLUGIN_STATES,
94 
95   /** External files for plugin states, under the
96    * STATES dir. */
97   PROJECT_PATH_PLUGIN_EXT_COPIES,
98 
99   /** External files for plugin states, under the
100    * STATES dir. */
101   PROJECT_PATH_PLUGIN_EXT_LINKS,
102 
103   PROJECT_PATH_EXPORTS,
104 
105   /* PROJECT_PATH_EXPORTS / "stems". */
106   PROJECT_PATH_EXPORTS_STEMS,
107 
108   PROJECT_PATH_POOL,
109 } ProjectPath;
110 
111 /**
112  * Selection type, used for controlling which part
113  * of the interface is selected, for copy-paste,
114  * displaying info in the inspector, etc.
115  */
116 typedef enum SelectionType
117 {
118   /** Track selection in tracklist or mixer. */
119   SELECTION_TYPE_TRACKLIST,
120 
121   /** Timeline or pinned timeline. */
122   SELECTION_TYPE_TIMELINE,
123 
124   /** Insert selections in the mixer. */
125   SELECTION_TYPE_INSERT,
126 
127   /** MIDI FX selections in the mixer. */
128   SELECTION_TYPE_MIDI_FX,
129 
130   /** Instrument slot. */
131   SELECTION_TYPE_INSTRUMENT,
132 
133   /** Modulator slot. */
134   SELECTION_TYPE_MODULATOR,
135 
136   /** Editor arranger. */
137   SELECTION_TYPE_EDITOR,
138 } SelectionType;
139 
140 static const cyaml_strval_t
141 selection_type_strings[] =
142 {
143   { "Tracklist", SELECTION_TYPE_TRACKLIST },
144   { "Timeline", SELECTION_TYPE_TIMELINE },
145   { "Insert", SELECTION_TYPE_INSERT },
146   { "MIDI FX", SELECTION_TYPE_MIDI_FX },
147   { "Instrument", SELECTION_TYPE_INSTRUMENT },
148   { "Modulator", SELECTION_TYPE_MODULATOR },
149   { "Editor", SELECTION_TYPE_EDITOR },
150 };
151 
152 /**
153  * Flag to pass to project_compress() and
154  * project_decompress().
155  */
156 typedef enum ProjectCompressionFlag
157 {
158   PROJECT_COMPRESS_FILE,
159   PROJECT_COMPRESS_DATA,
160 } ProjectCompressionFlag;
161 
162 #define PROJECT_DECOMPRESS_FILE \
163   PROJECT_COMPRESS_FILE
164 #define PROJECT_DECOMPRESS_DATA \
165   PROJECT_COMPRESS_DATA
166 
167 /**
168  * Contains all of the info that will be serialized
169  * into a project file.
170  */
171 typedef struct Project
172 {
173   int               schema_version;
174 
175   /** Project title. */
176   char *            title;
177 
178   /** Datetime string to add to the project file. */
179   char *            datetime_str;
180 
181   /** Path to save the project in. */
182   char *            dir;
183 
184   /**
185    * Backup dir to save the project during
186    * the current save call.
187    *
188    * For example, \ref Project.dir
189    * /backups/myproject.bak3.
190    */
191   char *            backup_dir;
192 
193   UndoManager *     undo_manager;
194 
195   Tracklist *       tracklist;
196 
197   /** Backend for the widget. */
198   ClipEditor *      clip_editor;
199 
200   /** Timeline widget backend. */
201   Timeline *        timeline;
202 
203   /** Snap/Grid info for the timeline. */
204   SnapGrid *        snap_grid_timeline;
205 
206   /** Snap/Grid info for the editor. */
207   SnapGrid *        snap_grid_editor;
208 
209   /** Quantize info for the timeline. */
210   QuantizeOptions * quantize_opts_timeline;
211 
212   /** Quantize info for the piano roll. */
213   QuantizeOptions * quantize_opts_editor;
214 
215   /**
216    * Selected objects in the
217    * AutomationArrangerWidget.
218    */
219   AutomationSelections * automation_selections;
220 
221   /**
222    * Selected objects in the audio editor.
223    */
224   AudioSelections * audio_selections;
225 
226   /**
227    * Selected objects in the
228    * ChordObjectArrangerWidget.
229    */
230   ChordSelections * chord_selections;
231 
232   /**
233    * Selected objects in the TimelineArrangerWidget.
234    */
235   TimelineSelections * timeline_selections;
236 
237   /**
238    * Selected MidiNote's in the MidiArrangerWidget.
239    */
240   MidiArrangerSelections * midi_arranger_selections;
241 
242   /**
243    * Selected Track's.
244    */
245   TracklistSelections * tracklist_selections;
246 
247   /**
248    * Plugin selections in the Mixer.
249    */
250   MixerSelections * mixer_selections;
251 
252   /** Zoom levels. TODO & move to clip_editor */
253   double            timeline_zoom;
254   double            piano_roll_zoom;
255 
256   /** Manager for region link groups. */
257   RegionLinkGroupManager * region_link_group_manager;
258 
259   PortConnectionsManager * port_connections_manager;
260 
261   /**
262    * The audio backend
263    */
264   AudioEngine *     audio_engine;
265 
266   /** MIDI bindings. */
267   MidiMappings *    midi_mappings;
268 
269   /**
270    * Currently selected tool (select - normal,
271    * select - stretch, edit, delete, ramp, audition)
272    */
273   Tool              tool;
274 
275   /**
276    * Whether the current is currently being loaded
277    * from a backup file.
278    *
279    * This is useful when instantiating plugins from
280    * state and should be set to false after the
281    * project is loaded.
282    */
283   bool              loading_from_backup;
284 
285   /**
286    * If a project is currently loaded or not.
287    *
288    * This is useful so that we know if we need to
289    * tear down when loading a new project while
290    * another one is loaded.
291    */
292   bool              loaded;
293 
294   /**
295    * The last thing selected in the GUI.
296    *
297    * Used in inspector_widget_refresh.
298    */
299   SelectionType     last_selection;
300 
301   /** Zrythm version, for serialization */
302   char *            version;
303 
304   /** Semaphore used to block saving. */
305   ZixSem            save_sem;
306 
307   gint64            last_autosave_time;
308 } Project;
309 
310 static const cyaml_schema_field_t
311   project_fields_schema[] =
312 {
313   YAML_FIELD_INT (
314     Project, schema_version),
315   YAML_FIELD_STRING_PTR (
316     Project, title),
317   YAML_FIELD_STRING_PTR (
318     Project, datetime_str),
319   YAML_FIELD_STRING_PTR (
320     Project, version),
321   YAML_FIELD_MAPPING_PTR (
322     Project, tracklist, tracklist_fields_schema),
323   YAML_FIELD_MAPPING_PTR (
324     Project, clip_editor,
325     clip_editor_fields_schema),
326   YAML_FIELD_MAPPING_PTR (
327     Project, timeline,
328     timeline_fields_schema),
329   YAML_FIELD_MAPPING_PTR (
330     Project, snap_grid_timeline,
331     snap_grid_fields_schema),
332   YAML_FIELD_MAPPING_PTR (
333     Project, snap_grid_editor,
334     snap_grid_fields_schema),
335   YAML_FIELD_MAPPING_PTR (
336     Project, quantize_opts_timeline,
337     quantize_options_fields_schema),
338   YAML_FIELD_MAPPING_PTR (
339     Project, quantize_opts_editor,
340     quantize_options_fields_schema),
341   YAML_FIELD_MAPPING_PTR (
342     Project, audio_engine, engine_fields_schema),
343   YAML_FIELD_MAPPING_PTR (
344     Project, mixer_selections,
345     mixer_selections_fields_schema),
346   YAML_FIELD_MAPPING_PTR (
347     Project, timeline_selections,
348     timeline_selections_fields_schema),
349   YAML_FIELD_MAPPING_PTR (
350     Project, midi_arranger_selections,
351     midi_arranger_selections_fields_schema),
352   YAML_FIELD_MAPPING_PTR (
353     Project, chord_selections,
354     chord_selections_fields_schema),
355   YAML_FIELD_MAPPING_PTR (
356     Project, automation_selections,
357     automation_selections_fields_schema),
358   YAML_FIELD_MAPPING_PTR (
359     Project, audio_selections,
360     audio_selections_fields_schema),
361   YAML_FIELD_MAPPING_PTR (
362     Project, tracklist_selections,
363     tracklist_selections_fields_schema),
364   YAML_FIELD_MAPPING_PTR (
365     Project, region_link_group_manager,
366     region_link_group_manager_fields_schema),
367   YAML_FIELD_MAPPING_PTR (
368     Project, port_connections_manager,
369     port_connections_manager_fields_schema),
370   YAML_FIELD_MAPPING_PTR (
371     Project, midi_mappings,
372     midi_mappings_fields_schema),
373   YAML_FIELD_MAPPING_PTR_OPTIONAL (
374     Project, undo_manager,
375     undo_manager_fields_schema),
376   YAML_FIELD_ENUM (
377     Project, last_selection,
378     selection_type_strings),
379 
380   CYAML_FIELD_END
381 };
382 
383 static const cyaml_schema_value_t
384   project_schema =
385 {
386   YAML_VALUE_PTR (
387     Project, project_fields_schema),
388 };
389 
390 /**
391  * Projet save data.
392  */
393 typedef struct ProjectSaveData
394 {
395   /** Project clone (with memcpy). */
396   Project * project;
397 
398   /** Full path to save to. */
399   char *    project_file_path;
400 
401   bool      is_backup;
402 
403   /** To be set to true when the thread finishes. */
404   bool      finished;
405 
406   bool      show_notification;
407 
408   /** Whether an error occured during saving. */
409   bool      has_error;
410 
411   GenericProgressInfo progress_info;
412 } ProjectSaveData;
413 
414 /**
415  * Checks that everything is okay with the project.
416  */
417 void
418 project_validate (Project * self);
419 
420 ArrangerSelections *
421 project_get_arranger_selections_for_last_selection (
422   Project * self);
423 
424 /**
425  * Creates a default project.
426  *
427  * This is only used internally or for generating
428  * projects from scripts.
429  *
430  * @param prj_dir The directory of the project to
431  *   create, including its title.
432  * @param headless Create the project assuming we
433  *   are running without a UI.
434  * @param start_engine Whether to also start the
435  *   engine after creating the project.
436  */
437 COLD
438 Project *
439 project_create_default (
440   Project *    self,
441   const char * prj_dir,
442   bool         headless,
443   bool         with_engine);
444 
445 /**
446  * If project has a filename set, it loads that.
447  * Otherwise it loads the default project.
448  *
449  * @param is_template Load the project as a
450  *   template and create a new project from it.
451  *
452  * @return 0 if successful, non-zero otherwise.
453  */
454 COLD
455 int
456 project_load (
457   const char * filename,
458   const bool   is_template);
459 
460 /**
461  * Saves the project to a project file in the
462  * given dir.
463  *
464  * @param is_backup 1 if this is a backup. Backups
465  *   will be saved as <original filename>.bak<num>.
466  * @param show_notification Show a notification
467  *   in the UI that the project was saved.
468  * @param async Save asynchronously in another
469  *   thread.
470  *
471  * @return Non-zero if error.
472  */
473 int
474 project_save (
475   Project *    self,
476   const char * _dir,
477   const bool   is_backup,
478   const bool   show_notification,
479   const bool   async);
480 
481 /**
482  * Autosave callback.
483  *
484  * This will keep getting called at regular short
485  * intervals, and if enough time has passed and
486  * it's okay to save it will autosave, otherwise it
487  * will wait until the next interval and check
488  * again.
489  */
490 int
491 project_autosave_cb (
492   void * data);
493 
494 /**
495  * Returns the requested project path as a newly
496  * allocated string.
497  *
498  * @param backup Whether to get the path for the
499  *   current backup instead of the main project.
500  */
501 char *
502 project_get_path (
503   Project *     self,
504   ProjectPath   path,
505   bool          backup);
506 
507 /**
508  * Initializes the selections in the project.
509  *
510  * @note
511  * Not meant to be used anywhere besides
512  * tests and project.c
513  */
514 COLD
515 void
516 project_init_selections (Project * self);
517 
518 /**
519  * Compresses/decompress a project from a file/data
520  * to a file/data.
521  *
522  * @param compress True to compress, false to
523  *   decompress.
524  * @param[out] _dest Pointer to a location to allocate
525  *   memory.
526  * @param[out] _dest_size Pointer to a location to
527  *   store the size of the allocated memory.
528  * @param _src Input buffer or filepath.
529  * @param _src_size Input buffer size, if not
530  *   filepath.
531  *
532  * @return Whether successful.
533  */
534 bool
535 _project_compress (
536   bool                   compress,
537   char **                _dest,
538   size_t *               _dest_size,
539   ProjectCompressionFlag dest_type,
540   const char *           _src,
541   const size_t           _src_size,
542   ProjectCompressionFlag src_type,
543   GError **              error);
544 
545 #define project_compress(a,b,c,d,e,f,error) \
546   _project_compress (true, a, b, c, d, e, f, error)
547 
548 #define project_decompress(a,b,c,d,e,f,error) \
549   _project_compress (false, a, b, c, d, e, f, error)
550 
551 /**
552  * Returns the YAML representation of the saved
553  * project file.
554  *
555  * To be free'd with free().
556  *
557  * @param backup Whether to use the project file
558  *   from the most recent backup.
559  */
560 char *
561 project_get_existing_yaml (
562   Project * self,
563   bool      backup);
564 
565 /**
566  * Deep-clones the given project.
567  *
568  * To be used during save on the main thread.
569  */
570 NONNULL
571 Project *
572 project_clone (
573   const Project * src);
574 
575 /**
576  * Creates an empty project object.
577  */
578 COLD
579 Project *
580 project_new (
581   Zrythm * zrythm);
582 
583 /**
584  * Tears down the project.
585  */
586 void
587 project_free (Project * self);
588 
589 /**
590  * @}
591  */
592 
593 #endif
594