You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
591 lines
13 KiB
591 lines
13 KiB
// SPDX-FileCopyrightText: © 2018-2022 Alexandros Theodotou <alex@zrythm.org> |
|
// SPDX-License-Identifier: LicenseRef-ZrythmLicense |
|
|
|
/** |
|
* \file |
|
* |
|
* A project (or song), containing all the project |
|
* data as opposed to zrythm_app.h which manages |
|
* global things like plugin descriptors and global |
|
* settings. |
|
*/ |
|
|
|
#ifndef __PROJECT_H__ |
|
#define __PROJECT_H__ |
|
|
|
#include "actions/undo_manager.h" |
|
#include "audio/engine.h" |
|
#include "audio/midi_mapping.h" |
|
#include "audio/midi_note.h" |
|
#include "audio/port.h" |
|
#include "audio/port_connections_manager.h" |
|
#include "audio/quantize_options.h" |
|
#include "audio/region.h" |
|
#include "audio/region_link_group_manager.h" |
|
#include "audio/tracklist.h" |
|
#include "gui/backend/audio_selections.h" |
|
#include "gui/backend/automation_selections.h" |
|
#include "gui/backend/chord_selections.h" |
|
#include "gui/backend/clip_editor.h" |
|
#include "gui/backend/midi_arranger_selections.h" |
|
#include "gui/backend/mixer_selections.h" |
|
#include "gui/backend/timeline.h" |
|
#include "gui/backend/timeline_selections.h" |
|
#include "gui/backend/tool.h" |
|
#include "plugins/plugin.h" |
|
#include "zrythm.h" |
|
|
|
#include <gtk/gtk.h> |
|
|
|
#include <zix/sem.h> |
|
|
|
typedef struct Timeline Timeline; |
|
typedef struct Transport Transport; |
|
typedef struct Tracklist Tracklist; |
|
typedef struct TracklistSelections TracklistSelections; |
|
|
|
/** |
|
* @addtogroup project Project |
|
* |
|
* @{ |
|
*/ |
|
|
|
#define PROJECT_SCHEMA_VERSION 2 |
|
|
|
#define PROJECT ZRYTHM->project |
|
#define DEFAULT_PROJECT_NAME "Untitled Project" |
|
#define PROJECT_FILE "project.zpj" |
|
#define PROJECT_BACKUPS_DIR "backups" |
|
#define PROJECT_PLUGINS_DIR "plugins" |
|
#define PROJECT_PLUGIN_STATES_DIR "states" |
|
#define PROJECT_PLUGIN_EXT_COPIES_DIR "ext_file_copies" |
|
#define PROJECT_PLUGIN_EXT_LINKS_DIR "ext_file_links" |
|
#define PROJECT_EXPORTS_DIR "exports" |
|
#define PROJECT_STEMS_DIR "stems" |
|
#define PROJECT_POOL_DIR "pool" |
|
|
|
typedef enum ProjectPath |
|
{ |
|
PROJECT_PATH_PROJECT_FILE, |
|
PROJECT_PATH_BACKUPS, |
|
|
|
/** Plugins path. */ |
|
PROJECT_PATH_PLUGINS, |
|
|
|
/** Path for state .ttl files. */ |
|
PROJECT_PATH_PLUGIN_STATES, |
|
|
|
/** External files for plugin states, under the |
|
* STATES dir. */ |
|
PROJECT_PATH_PLUGIN_EXT_COPIES, |
|
|
|
/** External files for plugin states, under the |
|
* STATES dir. */ |
|
PROJECT_PATH_PLUGIN_EXT_LINKS, |
|
|
|
PROJECT_PATH_EXPORTS, |
|
|
|
/* PROJECT_PATH_EXPORTS / "stems". */ |
|
PROJECT_PATH_EXPORTS_STEMS, |
|
|
|
PROJECT_PATH_POOL, |
|
} ProjectPath; |
|
|
|
/** |
|
* Selection type, used for controlling which part |
|
* of the interface is selected, for copy-paste, |
|
* displaying info in the inspector, etc. |
|
*/ |
|
typedef enum SelectionType |
|
{ |
|
/** Track selection in tracklist or mixer. */ |
|
SELECTION_TYPE_TRACKLIST, |
|
|
|
/** Timeline or pinned timeline. */ |
|
SELECTION_TYPE_TIMELINE, |
|
|
|
/** Insert selections in the mixer. */ |
|
SELECTION_TYPE_INSERT, |
|
|
|
/** MIDI FX selections in the mixer. */ |
|
SELECTION_TYPE_MIDI_FX, |
|
|
|
/** Instrument slot. */ |
|
SELECTION_TYPE_INSTRUMENT, |
|
|
|
/** Modulator slot. */ |
|
SELECTION_TYPE_MODULATOR, |
|
|
|
/** Editor arranger. */ |
|
SELECTION_TYPE_EDITOR, |
|
} SelectionType; |
|
|
|
static const cyaml_strval_t selection_type_strings[] = { |
|
{"Tracklist", SELECTION_TYPE_TRACKLIST }, |
|
{ "Timeline", SELECTION_TYPE_TIMELINE }, |
|
{ "Insert", SELECTION_TYPE_INSERT }, |
|
{ "MIDI FX", SELECTION_TYPE_MIDI_FX }, |
|
{ "Instrument", SELECTION_TYPE_INSTRUMENT}, |
|
{ "Modulator", SELECTION_TYPE_MODULATOR }, |
|
{ "Editor", SELECTION_TYPE_EDITOR }, |
|
}; |
|
|
|
/** |
|
* Flag to pass to project_compress() and |
|
* project_decompress(). |
|
*/ |
|
typedef enum ProjectCompressionFlag |
|
{ |
|
PROJECT_COMPRESS_FILE, |
|
PROJECT_COMPRESS_DATA, |
|
} ProjectCompressionFlag; |
|
|
|
#define PROJECT_DECOMPRESS_FILE PROJECT_COMPRESS_FILE |
|
#define PROJECT_DECOMPRESS_DATA PROJECT_COMPRESS_DATA |
|
|
|
/** |
|
* Contains all of the info that will be serialized |
|
* into a project file. |
|
*/ |
|
typedef struct Project |
|
{ |
|
int schema_version; |
|
|
|
/** Project title. */ |
|
char * title; |
|
|
|
/** Datetime string to add to the project file. */ |
|
char * datetime_str; |
|
|
|
/** Path to save the project in. */ |
|
char * dir; |
|
|
|
/** |
|
* Backup dir to save the project during |
|
* the current save call. |
|
* |
|
* For example, \ref Project.dir |
|
* /backups/myproject.bak3. |
|
*/ |
|
char * backup_dir; |
|
|
|
UndoManager * undo_manager; |
|
|
|
Tracklist * tracklist; |
|
|
|
/** Backend for the widget. */ |
|
ClipEditor * clip_editor; |
|
|
|
/** Timeline widget backend. */ |
|
Timeline * timeline; |
|
|
|
/** Snap/Grid info for the timeline. */ |
|
SnapGrid * snap_grid_timeline; |
|
|
|
/** Snap/Grid info for the editor. */ |
|
SnapGrid * snap_grid_editor; |
|
|
|
/** Quantize info for the timeline. */ |
|
QuantizeOptions * quantize_opts_timeline; |
|
|
|
/** Quantize info for the piano roll. */ |
|
QuantizeOptions * quantize_opts_editor; |
|
|
|
/** |
|
* Selected objects in the |
|
* AutomationArrangerWidget. |
|
*/ |
|
AutomationSelections * automation_selections; |
|
|
|
/** |
|
* Selected objects in the audio editor. |
|
*/ |
|
AudioSelections * audio_selections; |
|
|
|
/** |
|
* Selected objects in the |
|
* ChordObjectArrangerWidget. |
|
*/ |
|
ChordSelections * chord_selections; |
|
|
|
/** |
|
* Selected objects in the TimelineArrangerWidget. |
|
*/ |
|
TimelineSelections * timeline_selections; |
|
|
|
/** |
|
* Selected MidiNote's in the MidiArrangerWidget. |
|
*/ |
|
MidiArrangerSelections * midi_arranger_selections; |
|
|
|
/** |
|
* Selected Track's. |
|
*/ |
|
TracklistSelections * tracklist_selections; |
|
|
|
/** |
|
* Plugin selections in the Mixer. |
|
*/ |
|
MixerSelections * mixer_selections; |
|
|
|
/** Zoom levels. TODO & move to clip_editor */ |
|
double timeline_zoom; |
|
double piano_roll_zoom; |
|
|
|
/** Manager for region link groups. */ |
|
RegionLinkGroupManager * region_link_group_manager; |
|
|
|
PortConnectionsManager * port_connections_manager; |
|
|
|
/** |
|
* The audio backend |
|
*/ |
|
AudioEngine * audio_engine; |
|
|
|
/** MIDI bindings. */ |
|
MidiMappings * midi_mappings; |
|
|
|
/** |
|
* Currently selected tool (select - normal, |
|
* select - stretch, edit, delete, ramp, audition) |
|
*/ |
|
Tool tool; |
|
|
|
/** |
|
* Whether the current is currently being loaded |
|
* from a backup file. |
|
* |
|
* This is useful when instantiating plugins from |
|
* state and should be set to false after the |
|
* project is loaded. |
|
*/ |
|
bool loading_from_backup; |
|
|
|
/** |
|
* If a project is currently loaded or not. |
|
* |
|
* This is useful so that we know if we need to |
|
* tear down when loading a new project while |
|
* another one is loaded. |
|
*/ |
|
bool loaded; |
|
|
|
/** |
|
* The last thing selected in the GUI. |
|
* |
|
* Used in inspector_widget_refresh. |
|
*/ |
|
SelectionType last_selection; |
|
|
|
/** Zrythm version, for serialization */ |
|
char * version; |
|
|
|
/** Semaphore used to block saving. */ |
|
ZixSem save_sem; |
|
|
|
/** Used to check if the project has unsaved |
|
* changes. */ |
|
UndoableAction * last_saved_action; |
|
|
|
gint64 last_autosave_time; |
|
} Project; |
|
|
|
static const cyaml_schema_field_t project_fields_schema[] = { |
|
YAML_FIELD_INT (Project, schema_version), |
|
YAML_FIELD_STRING_PTR (Project, title), |
|
YAML_FIELD_STRING_PTR (Project, datetime_str), |
|
YAML_FIELD_STRING_PTR (Project, version), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
tracklist, |
|
tracklist_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
clip_editor, |
|
clip_editor_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
timeline, |
|
timeline_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
snap_grid_timeline, |
|
snap_grid_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
snap_grid_editor, |
|
snap_grid_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
quantize_opts_timeline, |
|
quantize_options_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
quantize_opts_editor, |
|
quantize_options_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
audio_engine, |
|
engine_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
mixer_selections, |
|
mixer_selections_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
timeline_selections, |
|
timeline_selections_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
midi_arranger_selections, |
|
midi_arranger_selections_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
chord_selections, |
|
chord_selections_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
automation_selections, |
|
automation_selections_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
audio_selections, |
|
audio_selections_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
tracklist_selections, |
|
tracklist_selections_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
region_link_group_manager, |
|
region_link_group_manager_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
port_connections_manager, |
|
port_connections_manager_fields_schema), |
|
YAML_FIELD_MAPPING_PTR ( |
|
Project, |
|
midi_mappings, |
|
midi_mappings_fields_schema), |
|
YAML_FIELD_MAPPING_PTR_OPTIONAL ( |
|
Project, |
|
undo_manager, |
|
undo_manager_fields_schema), |
|
YAML_FIELD_ENUM ( |
|
Project, |
|
last_selection, |
|
selection_type_strings), |
|
|
|
CYAML_FIELD_END |
|
}; |
|
|
|
static const cyaml_schema_value_t project_schema = { |
|
YAML_VALUE_PTR (Project, project_fields_schema), |
|
}; |
|
|
|
/** |
|
* Project save data. |
|
*/ |
|
typedef struct ProjectSaveData |
|
{ |
|
/** Project clone (with memcpy). */ |
|
Project * project; |
|
|
|
/** Full path to save to. */ |
|
char * project_file_path; |
|
|
|
bool is_backup; |
|
|
|
/** To be set to true when the thread finishes. */ |
|
bool finished; |
|
|
|
bool show_notification; |
|
|
|
/** Whether an error occurred during saving. */ |
|
bool has_error; |
|
|
|
GenericProgressInfo progress_info; |
|
} ProjectSaveData; |
|
|
|
/** |
|
* Checks that everything is okay with the project. |
|
*/ |
|
void |
|
project_validate (Project * self); |
|
|
|
ArrangerSelections * |
|
project_get_arranger_selections_for_last_selection ( |
|
Project * self); |
|
|
|
/** |
|
* Creates a default project. |
|
* |
|
* This is only used internally or for generating |
|
* projects from scripts. |
|
* |
|
* @param prj_dir The directory of the project to |
|
* create, including its title. |
|
* @param headless Create the project assuming we |
|
* are running without a UI. |
|
* @param start_engine Whether to also start the |
|
* engine after creating the project. |
|
*/ |
|
COLD Project * |
|
project_create_default ( |
|
Project * self, |
|
const char * prj_dir, |
|
bool headless, |
|
bool with_engine); |
|
|
|
/** |
|
* If project has a filename set, it loads that. |
|
* Otherwise it loads the default project. |
|
* |
|
* @param is_template Load the project as a |
|
* template and create a new project from it. |
|
* |
|
* @return 0 if successful, non-zero otherwise. |
|
*/ |
|
COLD int |
|
project_load (const char * filename, const bool is_template); |
|
|
|
/** |
|
* Saves the project to a project file in the |
|
* given dir. |
|
* |
|
* @param is_backup 1 if this is a backup. Backups |
|
* will be saved as <original filename>.bak<num>. |
|
* @param show_notification Show a notification |
|
* in the UI that the project was saved. |
|
* @param async Save asynchronously in another |
|
* thread. |
|
* |
|
* @return Non-zero if error. |
|
*/ |
|
int |
|
project_save ( |
|
Project * self, |
|
const char * _dir, |
|
const bool is_backup, |
|
const bool show_notification, |
|
const bool async); |
|
|
|
/** |
|
* Autosave callback. |
|
* |
|
* This will keep getting called at regular short |
|
* intervals, and if enough time has passed and |
|
* it's okay to save it will autosave, otherwise it |
|
* will wait until the next interval and check |
|
* again. |
|
*/ |
|
int |
|
project_autosave_cb (void * data); |
|
|
|
/** |
|
* Returns the requested project path as a newly |
|
* allocated string. |
|
* |
|
* @param backup Whether to get the path for the |
|
* current backup instead of the main project. |
|
*/ |
|
MALLOC |
|
NONNULL |
|
char * |
|
project_get_path (Project * self, ProjectPath path, bool backup); |
|
|
|
/** |
|
* Initializes the selections in the project. |
|
* |
|
* @note |
|
* Not meant to be used anywhere besides |
|
* tests and project.c |
|
*/ |
|
COLD void |
|
project_init_selections (Project * self); |
|
|
|
/** |
|
* Compresses/decompress a project from a file/data |
|
* to a file/data. |
|
* |
|
* @param compress True to compress, false to |
|
* decompress. |
|
* @param[out] _dest Pointer to a location to allocate |
|
* memory. |
|
* @param[out] _dest_size Pointer to a location to |
|
* store the size of the allocated memory. |
|
* @param _src Input buffer or filepath. |
|
* @param _src_size Input buffer size, if not |
|
* filepath. |
|
* |
|
* @return Whether successful. |
|
*/ |
|
bool |
|
_project_compress ( |
|
bool compress, |
|
char ** _dest, |
|
size_t * _dest_size, |
|
ProjectCompressionFlag dest_type, |
|
const char * _src, |
|
const size_t _src_size, |
|
ProjectCompressionFlag src_type, |
|
GError ** error); |
|
|
|
#define project_compress(a, b, c, d, e, f, error) \ |
|
_project_compress (true, a, b, c, d, e, f, error) |
|
|
|
#define project_decompress(a, b, c, d, e, f, error) \ |
|
_project_compress (false, a, b, c, d, e, f, error) |
|
|
|
/** |
|
* Returns the YAML representation of the saved |
|
* project file. |
|
* |
|
* To be free'd with free(). |
|
* |
|
* @param backup Whether to use the project file |
|
* from the most recent backup. |
|
*/ |
|
char * |
|
project_get_existing_yaml ( |
|
Project * self, |
|
bool backup, |
|
GError ** error); |
|
|
|
/** |
|
* Deep-clones the given project. |
|
* |
|
* To be used during save on the main thread. |
|
* |
|
* @param for_backup Whether the resulting project |
|
* is for a backup. |
|
*/ |
|
NONNULL |
|
Project * |
|
project_clone (const Project * src, bool for_backup); |
|
|
|
/** |
|
* Creates an empty project object. |
|
*/ |
|
COLD Project * |
|
project_new (Zrythm * zrythm); |
|
|
|
/** |
|
* Upgrades the given project YAML's schema if needed. |
|
* |
|
* @return True if the schema was upgraded. |
|
*/ |
|
COLD bool |
|
project_upgrade_schema (char ** yaml, int src_ver); |
|
|
|
/** |
|
* Tears down the project. |
|
*/ |
|
void |
|
project_free (Project * self); |
|
|
|
/** |
|
* @} |
|
*/ |
|
|
|
#endif
|
|
|