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