Skip to content

Commit

Permalink
autosave proj every 2min if sequencer not running
Browse files Browse the repository at this point in the history
also improve code docs for mainloop, events and clock tick event
  • Loading branch information
maks committed Feb 12, 2025
1 parent 9ac64ab commit 42affae
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 6 deletions.
15 changes: 14 additions & 1 deletion docs/DEV.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,17 @@ A helpful tool for debugging MIDI output is [ShowMIDI](https://github.com/gbevin

### USB MIDI output

TODO
TODO

## Notes on code structure

### Key classes

Some classes are worth documenting specifically here as they contain key pieces of functionality.

`sources/Adapters/picoTracker/gui/picoTrackerEventManager.cpp`

`picoTrackerEventManager` is important because it's where `MainLoop()` is and hence it's where "events" are dispatched.
It is also here that the 1ms tick timer callback is set up and the callback function for it is found: `timerHandler()`. The `timerHandler()` function is then the source of the `PICO_CLOCK` events, which are then dispatched to the `picoTrackerEventQueue` at the rate of 1Hz.

`AppWindow::AnimationUpdate()` is the handy spot where we handle calling autosave just because of the convienence of the `AppWindow` class having easy access to the player, the current project name and the persistance service.
7 changes: 4 additions & 3 deletions sources/Adapters/picoTracker/gui/picoTrackerEventManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ picoTrackerEventQueue *queue;
char inBuffer[INPUT_BUFFER_SIZE];
#endif

// timer callback at a rate of 1kHz (from a 1ms hardware interrupt timer)
bool timerHandler(repeating_timer_t *rt) {
queue = picoTrackerEventQueue::GetInstance();
gTime_++;

// send a clock (PICO_CLOCK) event once every second
if (gTime_ % 1000 == 0) {
queue->push(picoTrackerEvent(PICO_CLOCK));
}
Expand All @@ -58,9 +61,7 @@ bool picoTrackerEventManager::Init() {

keyboardCS_ = new KeyboardControllerSource("keyboard");

// TODO: fix this, there is a timer service that should be used. Also all of
// this keyRepeat logic is already implemented in the eventdispatcher
// Application/Commands/EventDispatcher.cpp
// setup a repeating timer for 1ms ticks
add_repeating_timer_ms(1, timerHandler, NULL, &timer_);
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "Adapters/picoTracker/utils/utils.h"
#include "Application/Model/Config.h"
#include "Application/Utils/char.h"
#include "Player/Player.h"
#include "System/Console/Trace.h"
#include "System/System/System.h"
#include "UIFramework/BasicDatas/GUIEvent.h"
Expand Down
27 changes: 27 additions & 0 deletions sources/Application/AppWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <nanoprintf.h>
#include <string.h>

const u_int16_t AUTOSAVE_INTERVAL_IN_SECONDS = 2 * 60;

AppWindow *instance = 0;

unsigned char AppWindow::_charScreen[SCREEN_CHARS];
Expand Down Expand Up @@ -495,6 +497,18 @@ void AppWindow::AnimationUpdate() {
loadProject_ = false;
}
_currentView->AnimationUpdate();

// *attempt* to auto save every AUTOSAVE_INTERVAL_IN_MILLIS
// will return false if auto save was unsuccessful because eg. the sequencer
// is running
// we do this here because for sheer convenience because this
// callback is called every second and we have easy access in this class to
// the player, projectname and persistence service
if (++lastAutoSave > AUTOSAVE_INTERVAL_IN_SECONDS) {
if (autoSave()) {
lastAutoSave = 0;
}
}
}

void AppWindow::LayoutChildren(){};
Expand Down Expand Up @@ -616,3 +630,16 @@ void AppWindow::Print(char *line) {
};

void AppWindow::SetColor(ColorDefinition cd) { colorIndex_ = cd; };

bool AppWindow::autoSave() {
Player *player = Player::GetInstance();
// only auto save when sequencer is not running
if (!player->IsRunning()) {
Trace::Log("APPWINDOW", "AutoSaving Project Data");
// get persistence service and call autosave
PersistencyService *ps = PersistencyService::GetInstance();
ps->AutoSaveProjectData(projectName_);
return true;
}
return false;
}
4 changes: 4 additions & 0 deletions sources/Application/AppWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ class AppWindow : public GUIWindow, I_Observer, Status {
void onQuitApp();

private:
bool autoSave();

View *_currentView;
ViewData *_viewData;
SongView *_songView;
Expand Down Expand Up @@ -120,6 +122,8 @@ class AppWindow : public GUIWindow, I_Observer, Status {
SysMutex drawMutex_;

bool loadProject_ = false;

uint32_t lastAutoSave = 0;
};

#endif
10 changes: 8 additions & 2 deletions sources/Application/Persistency/PersistencyService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,15 @@ PersistencyResult PersistencyService::SaveProjectData(const char *projectName,
fp->Close();
delete (fp);

// if *not* doing auto save, then we need to delete the existing autosave
// if we are doing an explicit save (ie nto a autosave), then we need to
// delete the existing autosave file so that this explicit save will be loaded
// in case subsequent autosave has changes the user doesn't want to keep
if (!autosave) {
etl::vector segments = {PROJECTS_DIR, projectName, AUTO_SAVE_FILENAME};
CreatePath(pathBufferA, segments);
picoFS->DeleteFile(pathBufferA.c_str());
Trace::Log("PERSISTENCYSERVICE", "Deleted Autosave File: %s\n",
pathBufferA.c_str());
}

return PERSIST_SAVED;
Expand Down Expand Up @@ -228,7 +232,9 @@ void PersistencyService::CreatePath(
path.clear();
// iterate over segments and concatenate using iterator
for (auto it = segments.begin(); it != segments.end(); ++it) {
path.append("/");
path.append(*it);
if (it != segments.end() - 1) {
path.append("/");
}
}
}

0 comments on commit 42affae

Please sign in to comment.