Editor_Workflows
The editor is a major subsystem of PDJE. It is reached through the PDJE facade, but it owns its own workflow around project-local state, typed timeline mutation, render and push behavior, preview playback, and edit-history operations. This page is the manual bridge between Core_Engine, Editor_Format, and the generated Class editorObject reference.
What The Editor Owns
The editor path in the current tree is responsible for:
project-local editing state rooted under the editor project path
timeline mutation for mix, note, music, and key-value style content
music metadata authoring and working-set management
render steps that prepare root-DB-ready payloads
push steps that persist selected authored results back into the root DB
history and time-travel operations exposed through editorObject
This means editor support is a core part of PDJE, not just an optional helper around InitEditor().
How The Editor Is Reached
The editor uses the same top-level facade as playback, but it follows a different lifecycle:
Construct PDJE with the root database path.
Call InitEditor() to prepare the editor path.
Use GetEditorObject() to access the editor subsystem.
Call CloseEditor() when the editor handle is no longer needed.
Playback and editor can coexist behind the same PDJE object, but playback and authoring should be treated as different workflows.
-
bool PDJE::InitEditor(const DONT_SANITIZE &auth_name, const DONT_SANITIZE &auth_email, const DONT_SANITIZE &projectRoot)
Initializes the editor.
- Parameters:
auth_name – The author’s name for Git commits.
auth_email – The author’s email for Git commits.
projectRoot – The root directory of the editor project.
- Returns:
trueif the editor was initialized successfully,falseotherwise.
-
inline std::shared_ptr<editorObject> PDJE::GetEditorObject()
editor handler getter api for binded codes. this function gives you a editor handler.
- Returns:
editorObject* the editor object. check nullptr before use.
-
inline void PDJE::CloseEditor()
Close the Editor object.
Project Setup
The public surface exposes two main starting modes.
New project / new authored content:
Call InitEditor() through PDJE.
Acquire the editorObject.
Use ConfigNewMusic() when you are creating new music metadata inside the editor project.
Open existing project / continue editing:
Call InitEditor() through PDJE.
Acquire the editorObject.
Use Open() when you need to reopen a specific editor project path through the editor handle.
The header documents that if PDJE already initialized the editor path for you, you do not need to call Open() again just to continue the same startup flow.
The editor also exposes DESTROY_PROJECT() for destructive project teardown. Treat that as a cleanup or reset tool, not part of the normal authoring loop.
-
bool editorObject::Open(const fs::path &projectPath, const DONT_SANITIZE &auth_name, const DONT_SANITIZE &auth_email)
Opens an existing editor project. if PDJE called InitEditor, you don’t need to call this again.
- Parameters:
projectPath – The path to the project.
- Returns:
trueif the project was opened successfully,falseotherwise.
-
bool editorObject::ConfigNewMusic(const UNSANITIZED &NewMusicName, const UNSANITIZED &composer, const fs::path &musicPath, const DONT_SANITIZE &firstBeat = "0")
Configures a new music entry.
- Parameters:
NewMusicName – The unsanitized name of the new music.
composer – The unsanitized composer of the new music.
musicPath – The path to the music file.
firstBeat – The first Beat of the music (defaults to “0”).
- Returns:
trueif the configuration was successful,falseotherwise.
-
DONT_SANITIZE editorObject::DESTROY_PROJECT()
Destroys the entire project.
Warning
This operation is irreversible.
- Returns:
A string indicating the result of the operation.
PDJE engine("root.db");
if (!engine.InitEditor("Author Name",
"author@example.com",
"project-root")) {
return;
}
auto editor = engine.GetEditorObject();
if (!editor) {
return;
}
(void)editor->ConfigNewMusic("Song",
"Composer",
"audio/song.wav",
"4800");
Mutation Workflow
editorObject exposes typed mutation operations rather than a single string-only edit API.
The current public argument families are:
EDIT_ARG_MUSIC music-entry oriented edits built around MusicArgs
EDIT_ARG_MIX timeline mix/event edits built around MixArgs
EDIT_ARG_NOTE note/chart edits built around NoteArgs
EDIT_ARG_KEY_VALUE key-value style project data
Operationally:
AddLine() appends or inserts authored data into the project-local editor state.
deleteLine() removes matching data from the project-local editor state.
getAll() is the readback-oriented path when you want to enumerate the current typed working data.
The working representation is tied to the editor/timeline stack and JSON-backed state. For on-disk key names and binary translation details, use Editor_Format.
EDIT_ARG_MIX mix;
mix.type = TypeEnum::FILTER;
mix.details = DetailEnum::LOW;
mix.ID = 1;
mix.first = "1"; // cosine-style interpolation selector in older examples
mix.second = "5000,1000,2000,3000,4000,5000,5500,6000";
mix.third = "";
mix.beat = 0;
mix.subBeat = 0;
mix.separate = 1;
mix.Ebeat = 16;
mix.EsubBeat = 0;
mix.Eseparate = 1;
(void)editor->AddLine(mix);
std::vector<EDIT_ARG_MIX> found;
editor->getAll<EDIT_ARG_MIX>(
[&found](const EDIT_ARG_MIX &row) {
if (row.beat < 32) {
found.push_back(row);
}
});
for (const auto &row : found) {
(void)editor->deleteLine(row, false, false);
}
Use the four typed families as the main mental model:
MusicArgs changes the BPM timeline or music metadata side of the project.
MixArgs changes runtime playback and effect timeline data.
NoteArgs changes chart and judgment-facing event data.
KEY_VALUE changes project-scoped auxiliary values.
History And Time Travel
The editor subsystem includes public history-oriented operations:
Undo()
Redo()
Go()
GetDiff()
GetLogWithJSONGraph()
UpdateLog()
Conceptually:
Undo() and Redo() expose edit-history navigation.
Go() exposes a direct history/time-travel style jump.
GetDiff() exposes semantic added/removed data between two editor commits.
GetLogWithJSONGraph() exposes log data in a graph-oriented JSON form.
UpdateLog() refreshes the editor-side history/log state after you need a new view of the commit timeline.
The public API contains multiple overloads and typed specializations for these operations, especially around the four edit families. Use Class editorObject when you need exact signatures or overload-level lookup.
The log JSON described in the older docs is still useful as the mental model:
LINE line-head entries with OID and TIME_STAMP
LOGS commit metadata with OID, BACK, AUTHOR, EMAIL, and TIME_STAMP
auto graph = editor->GetLogWithJSONGraph<EDIT_ARG_MIX>();
auto json = nlohmann::json::parse(graph);
auto commit_oid = json["LINE"].at(0)["OID"].get<std::string>();
(void)editor->Go<EDIT_ARG_MIX>(commit_oid);
(void)editor->Undo<EDIT_ARG_MIX>();
(void)editor->Redo<EDIT_ARG_MIX>();
editor->UpdateLog<EDIT_ARG_MIX>();
For diff operations, compare two commit OIDs from the same timeline.
editor->UpdateLog<EDIT_ARG_MIX>();
auto graph = nlohmann::json::parse(
editor->GetLogWithJSONGraph<EDIT_ARG_MIX>());
auto old_oid = graph["LOGS"].at(0)["OID"].get<std::string>();
auto new_oid = graph["LOGS"].at(1)["OID"].get<std::string>();
auto mix_diff = editor->GetDiff<EDIT_ARG_MIX>(old_oid, new_oid);
auto music_diff =
editor->GetDiff<EDIT_ARG_MUSIC>("Song", old_oid, new_oid);
if (mix_diff.has_value() && !mix_diff->Empty()) {
for (const auto &added : mix_diff->mixAdded) {
// consume added MixArgs rows
}
}
GetDiff() returns std::optional<PDJE_TIMELINE::TimeLineSemanticDiffResult>. Use has_value() to guard failure cases such as invalid OIDs or missing music targets, and then inspect the type-specific added/removed collections:
kvAdded / kvRemoved
mixAdded / mixRemoved
noteAdded / noteRemoved
musicBpmAdded / musicBpmRemoved
musicMetaAdded / musicMetaRemoved
EDIT_ARG_MUSIC uses a separate overload that requires the music name as the first argument.
Persistence Workflow
The current public surface exposes two persistence-oriented steps with distinct roles:
render() transforms project-local editor state into root-DB-ready content and performs the linter/render phase for a target track
pushToRootDB() writes selected track or music payloads into the root DB after the editor-side content is ready
Use this distinction when explaining the workflow:
render is the conversion and validation step
push is the persistence and write-back step
ConfigNewMusic() belongs here too, because it prepares music metadata that the render and push stages later consume.
render() also produces a lint message output. In the current implementation, track rendering builds trackdata plus related musdata payloads from the project-local JSON and binary state before pushToRootDB() writes them to the root database.
-
bool editorObject::render(const UNSANITIZED &trackTitle, litedb &ROOTDB, UNSANITIZED &lint_msg)
Renders the project data to the root database.
- Parameters:
trackTitle – The unsanitized title of the track to render.
ROOTDB – The root database to render to.
- Returns:
trueif the rendering was successful,falseotherwise.
-
bool editorObject::pushToRootDB(litedb &ROOTDB, const UNSANITIZED &trackTitleToPush)
Pushes a track to the root database.
- Parameters:
ROOTDB – The root database to push to.
trackTitleToPush – The unsanitized title of the track to push.
- Returns:
trueif the push was successful,falseotherwise.
-
bool editorObject::pushToRootDB(litedb &ROOTDB, const UNSANITIZED &musicTitle, const UNSANITIZED &musicComposer)
Pushes a music entry to the root database.
- Parameters:
ROOTDB – The root database to push to.
musicTitle – The unsanitized title of the music.
musicComposer – The unsanitized composer of the music.
- Returns:
trueif the push was successful,falseotherwise.
std::string lint_message;
if (!editor->render("track-title", *engine.DBROOT, lint_message)) {
return;
}
(void)editor->pushToRootDB(*engine.DBROOT, "track-title");
(void)editor->pushToRootDB(*engine.DBROOT, "Song", "Composer");
For the exact JSON keys, binary payloads, and timeline field meanings involved in those steps, use Editor_Format.
Preview And Validation
The editor also exposes a preview bridge:
demoPlayInit() prepares a demo-style audioPlayer from editor-authored content so you can audition the result without treating that preview step as the same thing as a root-DB persistence write
Validation and authoring support also span the wider editor tree, especially:
include/core/editor/
include/core/editor/pdjeLinter/
include/core/editor/TimeLine/
Initializes a demo player for a given track.
- Parameters:
player – [out] A shared pointer to the audio player to initialize.
frameBufferSize – The frame buffer size for the player.
trackTitle – The unsanitized title of the track to play.
std::shared_ptr<audioPlayer> preview;
editor->demoPlayInit(preview, 480, "track-title");
if (preview) {
(void)preview->Activate();
(void)preview->Deactivate();
}
Wrapper Notes
The strongest non-C++ wrapper coverage in the current tree still sits on the core/editor side. Older manuals contained large language matrices for every editor action. The restored guidance here keeps only the supportable workflow shape:
C++ remains the clearest reference for typed editor APIs.
SWIG bindings are oriented around the core/editor path, but exact wrapper helper names can differ from native C++.
The Godot-facing path exposes its own wrapper objects and helper methods rather than mirroring template-heavy C++ exactly.
Use Core_Engine for the wrapper entrypoints and the generated wrapper API when you need binding-specific method names.
How This Relates To The Older Manual
The old “Editor Step-1/2/3/4” flow maps onto this page as follows:
old Step-1, create/manage DB now lives in How The Editor Is Reached and Project Setup
old Step-2, edit/history control now lives in Mutation Workflow and History And Time Travel
old Step-3, configure new music, render, push now lives in Persistence Workflow
old Step-4, playback edited project now lives in Preview And Validation
This keeps the old conceptual flow without turning Core_Engine back into a single oversized editor manual.
Common Mistakes
Do not treat the editor as only InitEditor() plus a couple of helper calls.
Do not confuse editor JSON working data with root DB payloads.
Do not assume generated API overloads define the recommended workflow order.
Do not assume the playback flow alone explains authoring flow.
Do not treat preview playback as the same thing as render/push persistence.
Do not treat Editor_Format as the full editor manual; it explains data representations, not the operational workflow.