diff --git a/sources/Adapters/adv/gui/SerialDebugUI.cpp b/sources/Adapters/adv/gui/SerialDebugUI.cpp index 113673d37..a58899fe8 100644 --- a/sources/Adapters/adv/gui/SerialDebugUI.cpp +++ b/sources/Adapters/adv/gui/SerialDebugUI.cpp @@ -10,6 +10,7 @@ #include "../system/advSystem.h" #include "Adapters/adv/audio/record.h" #include "Application/Model/Config.h" +#include "Application/Utils/MemoryPool.h" #include "System/FileSystem/FileSystem.h" #include "System/FileSystem/I_File.h" #include "System/System/System.h" @@ -195,11 +196,13 @@ void SerialDebugUI::catFile(const char *path) { void SerialDebugUI::listFiles(const char *path) { auto fs = FileSystem::GetInstance(); + auto fileIndexList = MemoryPool::getFileIndexList(this); + if (!fs->chdir(path)) { Trace::Error("failed to ls files path:%s", path); } - etl::vector fileIndexes; - fs->list(&fileIndexes, "", false); + + fs->list(&(*fileIndexList), "", false); // No need to actually do the printing below for now as the current debug code // in PicoFileSystem class is already printing all the files fetched when the diff --git a/sources/Adapters/picoTracker/filesystem/picoTrackerFileSystem.cpp b/sources/Adapters/picoTracker/filesystem/picoTrackerFileSystem.cpp index fceebd5ee..3347a8447 100644 --- a/sources/Adapters/picoTracker/filesystem/picoTrackerFileSystem.cpp +++ b/sources/Adapters/picoTracker/filesystem/picoTrackerFileSystem.cpp @@ -7,6 +7,7 @@ */ #include "picoTrackerFileSystem.h" +#include "Application/Utils/MemoryPool.h" #include "Externals/etl/include/etl/pool.h" #include "pico/multicore.h" #include @@ -277,21 +278,27 @@ bool picoTrackerFileSystem::CopyFile(const char *srcFilename, auto fSrc = sd.open(srcFilename, O_READ); auto fDest = sd.open(destFilename, O_WRITE | O_CREAT); + auto buffer = MemoryPool::getBuffer(); + char *fileBuffer = buffer.data(); + int n = 0; - int bufferSize = sizeof(fileBuffer_); + while (true) { - n = fSrc.read(fileBuffer_, bufferSize); + n = fSrc.read(fileBuffer, MEMORYPOOL_SCRATCH_SIZE); // check for read error and only write if no error if (n >= 0) { - fDest.write(fileBuffer_, n); + fDest.write(fileBuffer, n); } else { Trace::Error("Failed to read file: %s", srcFilename); + fSrc.close(); + fDest.close(); return false; } - if (n < bufferSize) { + if ((size_t)n < MEMORYPOOL_SCRATCH_SIZE) { break; } } + fSrc.close(); fDest.close(); return true; diff --git a/sources/Adapters/picoTracker/filesystem/picoTrackerFileSystem.h b/sources/Adapters/picoTracker/filesystem/picoTrackerFileSystem.h index e17a02974..cf0a1d0b1 100644 --- a/sources/Adapters/picoTracker/filesystem/picoTrackerFileSystem.h +++ b/sources/Adapters/picoTracker/filesystem/picoTrackerFileSystem.h @@ -50,9 +50,6 @@ class picoTrackerFileSystem : public FileSystem { private: SdFs sd; void tolowercase(char *temp); - // buffer needs to be allocated here as too big for allocation as local - // variable on the stack - uint8_t fileBuffer_[512]; }; // Concrete implementation of PI_File for picoTracker diff --git a/sources/Adapters/picoTracker/gui/SerialDebugUI.cpp b/sources/Adapters/picoTracker/gui/SerialDebugUI.cpp index ef7e869a2..7f2a58d28 100644 --- a/sources/Adapters/picoTracker/gui/SerialDebugUI.cpp +++ b/sources/Adapters/picoTracker/gui/SerialDebugUI.cpp @@ -8,6 +8,7 @@ #include "SerialDebugUI.h" #include "Application/Model/Config.h" +#include "Application/Utils/MemoryPool.h" #include "System/FileSystem/FileSystem.h" #include "System/FileSystem/I_File.h" #include "hardware/uart.h" @@ -131,16 +132,17 @@ void SerialDebugUI::catFile(const char *path) { void SerialDebugUI::listFiles(const char *path) { auto fs = FileSystem::GetInstance(); + auto fileIndexList = MemoryPool::getFileIndexList(this); if (!fs->chdir(path)) { Trace::Error("failed to ls files path:%s", path); } - etl::vector fileIndexes; - fs->list(&fileIndexes, "", false); + + fs->list(&(*fileIndexList), "", false); char name[PFILENAME_SIZE]; - for (size_t i = 0; i < fileIndexes.size(); i++) { - fs->getFileName(fileIndexes[i], name, PFILENAME_SIZE); - if (fs->getFileType(fileIndexes[i]) == PFT_FILE) { + for (size_t i = 0; i < fileIndexList->size(); i++) { + fs->getFileName((*fileIndexList)[i], name, PFILENAME_SIZE); + if (fs->getFileType((*fileIndexList)[i]) == PFT_FILE) { printf("[file] %s\n", name); } else { printf("[dir] %s\n", name); diff --git a/sources/Application/AppWindow.cpp b/sources/Application/AppWindow.cpp index 5016c401e..c248a5a2f 100644 --- a/sources/Application/AppWindow.cpp +++ b/sources/Application/AppWindow.cpp @@ -152,8 +152,6 @@ AppWindow::AppWindow(I_GUIWindowImp &imp, const char *projectName) // Init all members - _statusLine[0] = 0; - _currentView = nullptr; _closeProject = false; _lastA = 0; diff --git a/sources/Application/AppWindow.h b/sources/Application/AppWindow.h index 278575d30..bb74e09ea 100644 --- a/sources/Application/AppWindow.h +++ b/sources/Application/AppWindow.h @@ -104,7 +104,6 @@ class AppWindow : public GUIWindow, I_Observer, Status { unsigned short _mask; unsigned long _lastA; unsigned long _lastB; - char _statusLine[80]; bool lowBatteryState_; bool lowBatteryMessageShown_; diff --git a/sources/Application/Audio/AudioFileStreamer.cpp b/sources/Application/Audio/AudioFileStreamer.cpp index 9ebefaaa6..0d7c02c81 100644 --- a/sources/Application/Audio/AudioFileStreamer.cpp +++ b/sources/Application/Audio/AudioFileStreamer.cpp @@ -9,6 +9,7 @@ #include "AudioFileStreamer.h" #include "Application/Model/Config.h" +#include "Application/Utils/MemoryPool.h" #include "Application/Utils/fixed.h" #include "Services/Audio/Audio.h" #include "System/Console/Trace.h" @@ -46,17 +47,16 @@ bool AudioFileStreamer::Start(const char *name, int startSample, bool looping) { return false; } - name_ = name; position_ = (startSample > 0) ? float(startSample) : 0.0f; #ifndef ADV stopRequested_ = false; #endif wav_.Close(); - Trace::Log("", "wave open:%s", name_.c_str()); - auto res = wav_.Open(name_.c_str()); + Trace::Log("", "wave open:%s", name); + auto res = wav_.Open(name); if (!res) { - Trace::Error("Failed to open streaming of file:%s", name_.c_str()); + Trace::Error("Failed to open streaming of file:%s", name); mode_ = AFSM_STOPPED; return false; } @@ -95,7 +95,7 @@ bool AudioFileStreamer::Start(const char *name, int startSample, bool looping) { fpSpeed_ = fl2fp(ratio); Trace::Debug("AudioFileStreamer: File '%s' - Sample Rate: %d Hz, Channels: " "%d", - name_.c_str(), fileSampleRate_, channels); + name, fileSampleRate_, channels); Trace::Debug("Size: %ld samples, Speed: %d", size, fp2i(fpSpeed_)); // Load the entire buffer for single cycle waveforms @@ -203,7 +203,7 @@ bool AudioFileStreamer::Render(fixed *buffer, int samplecount) { } // look if we have the file loaded if (!wav_.IsOpen()) { - Trace::Error("Failed to open streaming of file:%s", name_.c_str()); + Trace::Error("Failed to open streaming of file"); mode_ = AFSM_STOPPED; return false; } diff --git a/sources/Application/Audio/AudioFileStreamer.h b/sources/Application/Audio/AudioFileStreamer.h index bec3a50b5..fdb0f2360 100644 --- a/sources/Application/Audio/AudioFileStreamer.h +++ b/sources/Application/Audio/AudioFileStreamer.h @@ -32,7 +32,6 @@ class AudioFileStreamer : public AudioModule { protected: AudioFileStreamerMode mode_; - etl::string name_; WavFile wav_; float position_; Project *project_; diff --git a/sources/Application/Instruments/SamplePool.cpp b/sources/Application/Instruments/SamplePool.cpp index 03b3956da..6f42ef8da 100644 --- a/sources/Application/Instruments/SamplePool.cpp +++ b/sources/Application/Instruments/SamplePool.cpp @@ -11,6 +11,7 @@ #include "Application/Model/Config.h" #include "Application/Persistency/PersistencyService.h" #include "Application/Utils/DrawUtils.h" +#include "Application/Utils/MemoryPool.h" #include "Externals/SRC/common.h" #include "Externals/etl/include/etl/string.h" #include "Externals/etl/include/etl/string_stream.h" @@ -57,10 +58,11 @@ void SamplePool::Load(const char *projectName) { PROJECT_SAMPLES_DIR); } // First, find all wav files - etl::vector fileIndexes; - fs->list(&fileIndexes, ".wav", false); + auto fileIndexList = MemoryPool::getFileIndexList(this); + + fs->list(&(*fileIndexList), ".wav", false); char name[PFILENAME_SIZE]; - uint totalSamples = fileIndexes.size(); + uint totalSamples = fileIndexList->size(); // store for ui updates importCount = totalSamples; @@ -69,8 +71,8 @@ void SamplePool::Load(const char *projectName) { importIndex = i; importName = name; - fs->getFileName(fileIndexes[i], name, PFILENAME_SIZE); - if (fs->getFileType(fileIndexes[i]) == PFT_FILE) { + fs->getFileName((*fileIndexList)[i], name, PFILENAME_SIZE); + if (fs->getFileType((*fileIndexList)[i]) == PFT_FILE) { // Check if the filename exceeds the maximum allowed length if (strlen(name) > MAX_INSTRUMENT_FILENAME_LENGTH) { Trace::Error( diff --git a/sources/Application/Utils/CMakeLists.txt b/sources/Application/Utils/CMakeLists.txt index c7d11033d..ff1438d6a 100644 --- a/sources/Application/Utils/CMakeLists.txt +++ b/sources/Application/Utils/CMakeLists.txt @@ -1,4 +1,5 @@ add_library(application_utils + MemoryPool.cpp HexBuffers.cpp char.cpp fixed.cpp @@ -9,6 +10,12 @@ target_link_libraries(application_utils PUBLIC etl ) +if(NOT ADV) + target_link_libraries(application_utils PUBLIC + pico_sync + ) +endif() + target_include_directories(application_utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${PROJECT_SOURCE_DIR}) diff --git a/sources/Application/Utils/MemoryPool.cpp b/sources/Application/Utils/MemoryPool.cpp new file mode 100644 index 000000000..7b7c7493d --- /dev/null +++ b/sources/Application/Utils/MemoryPool.cpp @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2026 xiphonics, inc. + * + * This file is part of the picoTracker firmware + */ + +#include "MemoryPool.h" + +#ifdef ADV +#include "Adapters/adv/mutex/advMutex.h" +using Mutex = advMutex; +#else +#include "Adapters/picoTracker/mutex/picoTrackerMutex.h" +using Mutex = picoTrackerMutex; +#endif + +// globally available 1k scratch buffer for temporary use, e.g. for file +// loading, string rendering, file sorting +char MemoryPool::buffer_[MEMORYPOOL_SCRATCH_SIZE]; +static Mutex s_scratchBufferMutex; +SysMutex *MemoryPool::scratchBufferMutex_ = &s_scratchBufferMutex; + +// globally available list of file indexes for the current directory +etl::vector MemoryPool::fileIndexList_; +static Mutex s_fileIndexListMutex; +SysMutex *MemoryPool::fileIndexListMutex_ = &s_fileIndexListMutex; +const void *MemoryPool::fileIndexCurrentKey_ = nullptr; +int MemoryPool::fileIndexLockDepth_ = 0; diff --git a/sources/Application/Utils/MemoryPool.h b/sources/Application/Utils/MemoryPool.h new file mode 100644 index 000000000..eb60862ef --- /dev/null +++ b/sources/Application/Utils/MemoryPool.h @@ -0,0 +1,105 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2026 xiphonics, inc. + * + * This file is part of the picoTracker firmware + */ + +#pragma once + +#include "System/FileSystem/FileSystem.h" + +#include "ScopedLock.h" + +constexpr size_t MEMORYPOOL_SCRATCH_SIZE = 1024; + +class MemoryPool { +public: + template class ScopedRef { + public: + ScopedRef(T &resource, SysMutex &mutex) + : resource_(resource), lock_(mutex) {} + T *operator->() { return &resource_; } + T &operator*() { return resource_; } + ScopedRef(const ScopedRef &) = delete; + ScopedRef &operator=(const ScopedRef &) = delete; + + private: + T &resource_; + ScopedLock lock_; + }; + + // Scoped accessor for the raw scratch buffer. + // + // CORRECT: + // auto buf = MemoryPool::getBuffer(); + // char *p = buf.data(); // lock held until 'buf' goes out of scope + // + // WRONG - lock released immediately, p is unprotected: + // char *p = MemoryPool::getBuffer().data(); + class ScopedBuffer { + public: + ScopedBuffer(char *buf, SysMutex &m) : buf_(buf), lock_(m) {} + char *data() { return buf_; } + ScopedBuffer(const ScopedBuffer &) = delete; + ScopedBuffer &operator=(const ScopedBuffer &) = delete; + + private: + char *buf_; + ScopedLock lock_; + }; + + // Scoped accessor for the file index list with key-based recursive locking. + // + // Pass 'this' as the key so the same object can re-enter without deadlocking: + // auto list = MemoryPool::getFileIndexList(this); + // + // A different key (or the first caller) acquires the mutex; the same key + // simply increments a depth counter and skips re-locking. The mutex is + // released only when the depth reaches zero (outermost scope exits). + class KeyedScopedRef { + public: + using VecType = etl::vector; + + KeyedScopedRef(VecType &resource, SysMutex &mutex) + : resource_(resource), mutex_(mutex) {} + + ~KeyedScopedRef() { + if (--fileIndexLockDepth_ == 0) { + fileIndexCurrentKey_ = nullptr; + mutex_.Unlock(); + } + } + + VecType *operator->() { return &resource_; } + VecType &operator*() { return resource_; } + KeyedScopedRef(const KeyedScopedRef &) = delete; + KeyedScopedRef &operator=(const KeyedScopedRef &) = delete; + + private: + VecType &resource_; + SysMutex &mutex_; + }; + + [[nodiscard]] static KeyedScopedRef getFileIndexList(const void *key) { + if (fileIndexCurrentKey_ != key) { + fileIndexListMutex_->Lock(); + fileIndexCurrentKey_ = key; + } + ++fileIndexLockDepth_; + return {fileIndexList_, *fileIndexListMutex_}; + } + + [[nodiscard]] static ScopedBuffer getBuffer() { + return {buffer_, *scratchBufferMutex_}; + } + +private: + static char buffer_[MEMORYPOOL_SCRATCH_SIZE]; + static etl::vector fileIndexList_; + static SysMutex *fileIndexListMutex_; + static SysMutex *scratchBufferMutex_; + static const void *fileIndexCurrentKey_; + static int fileIndexLockDepth_; +}; \ No newline at end of file diff --git a/sources/Application/Utils/ScopedLock.h b/sources/Application/Utils/ScopedLock.h new file mode 100644 index 000000000..5574a4c62 --- /dev/null +++ b/sources/Application/Utils/ScopedLock.h @@ -0,0 +1,24 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2026 xiphonics, inc. + * + * This file is part of the picoTracker firmware + */ + +#pragma once + +#include "System/Process/SysMutex.h" + +// minimal RAII lock guard using the SysMutex interface ************************ + +class ScopedLock { +public: + explicit ScopedLock(SysMutex &m) : m_(m) { m_.Lock(); } + ~ScopedLock() { m_.Unlock(); } + ScopedLock(const ScopedLock &) = delete; + ScopedLock &operator=(const ScopedLock &) = delete; + +private: + SysMutex &m_; +}; \ No newline at end of file diff --git a/sources/Application/Views/ImportView.cpp b/sources/Application/Views/ImportView.cpp index 3be04c51b..bd4ab2219 100644 --- a/sources/Application/Views/ImportView.cpp +++ b/sources/Application/Views/ImportView.cpp @@ -8,9 +8,11 @@ */ #include "ImportView.h" + #include "Application/Audio/AudioFileStreamer.h" #include "Application/Instruments/SampleInstrument.h" #include "Application/Instruments/SamplePool.h" +#include "Application/Utils/MemoryPool.h" #include "Application/Views/SampleEditorView.h" #include "Externals/etl/include/etl/string.h" #include "Externals/etl/include/etl/to_string.h" @@ -63,13 +65,16 @@ void ImportView::Reset() { enterKeyHeld_ = false; pendingDirEnterOnRelease_ = false; inProjectSampleDir_ = false; - fileIndexList_.clear(); + auto fileIndexList = MemoryPool::getFileIndexList(this); + fileIndexList->clear(); } // Static method to set the source view type before opening ImportView void ImportView::SetSourceViewType(ViewType vt) { sourceViewType_ = vt; } void ImportView::ProcessButtonMask(unsigned short mask, bool pressed) { + auto fileIndexList = MemoryPool::getFileIndexList(this); + // Check for key release events if (!pressed) { // Open selected directory only when ENTER is released, unless ENTER was @@ -126,6 +131,8 @@ void ImportView::ProcessButtonMask(unsigned short mask, bool pressed) { return; } + unsigned fileIndex = (*fileIndexList)[currentIndex_]; + if (mask & EPBM_EDIT) { // Set flag to track that edit key is being held editKeyHeld_ = true; @@ -198,7 +205,7 @@ void ImportView::ProcessButtonMask(unsigned short mask, bool pressed) { return; // Do nothing if the list is empty } if (selectedButton_ == kProjectButtonEdit) { - unsigned fileIndex = fileIndexList_[currentIndex_]; + unsigned fileIndex = fileIndexList[currentIndex_]; char name[PFILENAME_SIZE]; fs->getFileName(fileIndex, name, PFILENAME_SIZE); showSampleEditor(name, false); @@ -249,7 +256,7 @@ void ImportView::ProcessButtonMask(unsigned short mask, bool pressed) { // handle changing selected "bottom button", note: ignore if this is a // nav+arrow combo if ((mask & EPBM_LEFT || mask & EPBM_RIGHT) && !(mask & EPBM_NAV)) { - if (inProjectSampleDir_ && fileIndexList_.empty()) { + if (inProjectSampleDir_ && fileIndexList->empty()) { return; // Do nothing if the list is empty } uint8_t buttonCount = inProjectSampleDir_ @@ -270,12 +277,12 @@ void ImportView::ProcessButtonMask(unsigned short mask, bool pressed) { // handle moving up and down the file list if (mask & EPBM_UP) { - if (inProjectSampleDir_ && fileIndexList_.empty()) { + if (inProjectSampleDir_ && fileIndexList->empty()) { return; // Do nothing if the list is empty } warpToNextSample(true); } else if (mask & EPBM_DOWN) { - if (inProjectSampleDir_ && fileIndexList_.empty()) { + if (inProjectSampleDir_ && fileIndexList->empty()) { return; // Do nothing if the list is empty } warpToNextSample(false); @@ -320,11 +327,13 @@ void ImportView::DrawView() { SamplePool::GetInstance()->GetAvailableSampleStorageSpace(); // Loop through visible files in the list + auto fileIndexList = MemoryPool::getFileIndexList(this); + for (size_t i = topIndex_; - i < topIndex_ + LIST_PAGE_SIZE && (i < fileIndexList_.size()); i++) { + i < topIndex_ + LIST_PAGE_SIZE && (i < fileIndexList->size()); i++) { props.invert_ = false; - unsigned fileIndex = fileIndexList_[i]; + unsigned fileIndex = (*fileIndexList)[i]; etl::string displayName; if (fs->getFileType(fileIndex) != PFT_DIR) { @@ -421,7 +430,7 @@ void ImportView::DrawView() { npf_snprintf(volField, sizeof(volField), "Vol:%2d", previewVolume); DrawString(x + 23, y, volField, props); } else { - if (fileIndexList_.empty()) { + if (fileIndexList->empty()) { // draw this a few lines down from *top* of screen SetColor(CD_NORMAL); props.invert_ = false; @@ -511,6 +520,7 @@ void ImportView::OnPlayerUpdate(PlayerEventType, unsigned int tick){}; void ImportView::OnFocus() { auto fs = FileSystem::GetInstance(); + auto fileIndexList = MemoryPool::getFileIndexList(this); toInstr_ = viewData_->currentInstrumentID_; @@ -525,6 +535,8 @@ void ImportView::OnFocus() { }; void ImportView::warpToNextSample(bool goUp) { + auto fileIndexList = MemoryPool::getFileIndexList(this); + if (goUp) { if (currentIndex_ > 0) { currentIndex_--; @@ -535,7 +547,7 @@ void ImportView::warpToNextSample(bool goUp) { } } } else { - if (currentIndex_ < fileIndexList_.size() - 1) { + if (currentIndex_ < fileIndexList->size() - 1) { currentIndex_++; // if we have scrolled off the bottom, page the file list down if not // at end of the list @@ -549,7 +561,9 @@ void ImportView::warpToNextSample(bool goUp) { void ImportView::preview(char *name) { auto fs = FileSystem::GetInstance(); - unsigned fileIndex = fileIndexList_[currentIndex_]; + auto fileIndexList = MemoryPool::getFileIndexList(this); + + unsigned fileIndex = (*fileIndexList)[currentIndex_]; // do not preview directories if (fs->getFileType(fileIndex) == PFT_DIR) { @@ -624,7 +638,8 @@ void ImportView::import() { auto fs = FileSystem::GetInstance(); char name[PFILENAME_SIZE]; - unsigned fileIndex = fileIndexList_[currentIndex_]; + auto fileIndexList = MemoryPool::getFileIndexList(this); + unsigned fileIndex = (*fileIndexList)[currentIndex_]; fs->getFileName(fileIndex, name, PFILENAME_SIZE); // Get current project name @@ -878,20 +893,24 @@ void ImportView::onConfirmRemoveProjectSample(View &, ModalView &dialog) { } void ImportView::refreshFileIndexList(FileSystem *fs) { - fs->list(&fileIndexList_, ".wav", false); + auto fileIndexList = MemoryPool::getFileIndexList(this); + + fs->list(&(*fileIndexList), ".wav", false); if (fs->isCurrentRoot() || inProjectSampleDir_) { - for (auto it = fileIndexList_.begin(); it != fileIndexList_.end(); ++it) { + for (auto it = (*fileIndexList).begin(); it != (*fileIndexList).end(); + ++it) { char entryName[PFILENAME_SIZE]; fs->getFileName(*it, entryName, PFILENAME_SIZE); if (strcmp(entryName, "..") == 0) { - fileIndexList_.erase(it); + (*fileIndexList).erase(it); break; } } } - if (currentIndex_ >= fileIndexList_.size()) { - currentIndex_ = fileIndexList_.empty() ? 0 : fileIndexList_.size() - 1; + size_t sz = (*fileIndexList).size(); + if (currentIndex_ >= sz) { + currentIndex_ = (*fileIndexList).empty() ? 0 : sz - 1; } } diff --git a/sources/Application/Views/ImportView.h b/sources/Application/Views/ImportView.h index fb365333d..d7b2aaec9 100644 --- a/sources/Application/Views/ImportView.h +++ b/sources/Application/Views/ImportView.h @@ -61,6 +61,5 @@ class ImportView : public ScreenView { false; // Flag to track if we're in the project's sample directory FileSystem *pendingDeleteFs_ = nullptr; char pendingDeleteFilename_[PFILENAME_SIZE] = {}; - etl::vector fileIndexList_; }; #endif diff --git a/sources/Application/Views/InstrumentImportView.cpp b/sources/Application/Views/InstrumentImportView.cpp index eda74d003..5342c2a52 100644 --- a/sources/Application/Views/InstrumentImportView.cpp +++ b/sources/Application/Views/InstrumentImportView.cpp @@ -11,6 +11,7 @@ #include "Application/AppWindow.h" #include "Application/Instruments/I_Instrument.h" #include "Application/Persistency/PersistencyService.h" +#include "Application/Utils/MemoryPool.h" #include "ModalDialogs/MessageBox.h" #include #include @@ -32,7 +33,8 @@ void InstrumentImportView::Reset() { currentIndex_ = 0; selected_ = 0; toInstrID_ = 0; - fileIndexList_.clear(); + auto fileIndexList = MemoryPool::getFileIndexList(this); + fileIndexList->clear(); } void InstrumentImportView::ProcessButtonMask(unsigned short mask, @@ -42,10 +44,12 @@ void InstrumentImportView::ProcessButtonMask(unsigned short mask, if (mask & EPBM_PLAY) { auto fs = FileSystem::GetInstance(); + auto fileIndexList = MemoryPool::getFileIndexList(this); + char name[PFILENAME_SIZE]; - if (currentIndex_ < fileIndexList_.size()) { - unsigned fileIndex = fileIndexList_[currentIndex_]; + if (currentIndex_ < fileIndexList->size()) { + unsigned fileIndex = (*fileIndexList)[currentIndex_]; fs->getFileName(fileIndex, name, PFILENAME_SIZE); if (mask & EPBM_ALT) { @@ -73,9 +77,10 @@ void InstrumentImportView::ProcessButtonMask(unsigned short mask, // ENTER modifier if (mask & EPBM_ENTER) { auto fs = FileSystem::GetInstance(); + auto fileIndexList = MemoryPool::getFileIndexList(this); - if (currentIndex_ < fileIndexList_.size()) { - unsigned fileIndex = fileIndexList_[currentIndex_]; + if (currentIndex_ < fileIndexList->size()) { + unsigned fileIndex = (*fileIndexList)[currentIndex_]; char name[PFILENAME_SIZE]; fs->getFileName(fileIndex, name, PFILENAME_SIZE); @@ -113,9 +118,11 @@ void InstrumentImportView::DrawView() { // need to use fullsize buffer as sdfat doesnt truncate if filename longer // than buffer but instead returns empty string in buffer :-( + auto fileIndexList = MemoryPool::getFileIndexList(this); char buffer[PFILENAME_SIZE]; + for (size_t i = topIndex_; - i < topIndex_ + LIST_PAGE_SIZE && (i < fileIndexList_.size()); i++) { + i < topIndex_ + LIST_PAGE_SIZE && (i < fileIndexList->size()); i++) { if (i == currentIndex_) { SetColor(CD_HILITE2); props.invert_ = true; @@ -125,7 +132,7 @@ void InstrumentImportView::DrawView() { } memset(buffer, '\0', sizeof(buffer)); - unsigned fileIndex = fileIndexList_[i]; + unsigned fileIndex = (*fileIndexList)[i]; fs->getFileName(fileIndex, buffer, PFILENAME_SIZE); if (fs->getFileType(fileIndex) == PFT_DIR) { @@ -151,7 +158,9 @@ void InstrumentImportView::OnFocus() { } void InstrumentImportView::warpToNextInstrument(bool goUp) { - if (fileIndexList_.empty()) + auto fileIndexList = MemoryPool::getFileIndexList(this); + + if (fileIndexList->empty()) return; if (goUp) { @@ -162,7 +171,7 @@ void InstrumentImportView::warpToNextInstrument(bool goUp) { } } } else { - if (currentIndex_ < fileIndexList_.size() - 1) { + if (currentIndex_ < fileIndexList->size() - 1) { currentIndex_++; if (currentIndex_ >= topIndex_ + LIST_PAGE_SIZE) { topIndex_ = currentIndex_ - LIST_PAGE_SIZE + 1; @@ -337,13 +346,16 @@ void InstrumentImportView::setCurrentFolder(FileSystem *fs, const char *name) { Trace::Error("FAILED to chdir to %s", name); return; } + + auto fileIndexList = MemoryPool::getFileIndexList(this); + currentIndex_ = 0; topIndex_ = 0; isDirty_ = true; // Update list of file indexes in this new dir - fileIndexList_.clear(); + fileIndexList->clear(); // Use false for subDirOnly to include both files and directories - fs->list(&fileIndexList_, INSTRUMENT_FILE_EXTENSION, false); - Trace::Debug("loaded %d files from %s", fileIndexList_.size(), name); + fs->list(&(*fileIndexList), INSTRUMENT_FILE_EXTENSION, false); + Trace::Debug("loaded %d files from %s", fileIndexList->size(), name); } diff --git a/sources/Application/Views/InstrumentImportView.h b/sources/Application/Views/InstrumentImportView.h index ebf309156..d22b88b02 100644 --- a/sources/Application/Views/InstrumentImportView.h +++ b/sources/Application/Views/InstrumentImportView.h @@ -37,6 +37,5 @@ class InstrumentImportView : public ScreenView { size_t currentIndex_ = 0; short selected_ = 0; int toInstrID_ = 0; - etl::vector fileIndexList_; }; #endif diff --git a/sources/Application/Views/SelectProjectView.cpp b/sources/Application/Views/SelectProjectView.cpp index e543e0a28..fa758c284 100644 --- a/sources/Application/Views/SelectProjectView.cpp +++ b/sources/Application/Views/SelectProjectView.cpp @@ -11,6 +11,7 @@ #include "Application/AppWindow.h" #include "Application/Persistency/PersistencyService.h" #include "Application/Utils/DrawUtils.h" +#include "Application/Utils/MemoryPool.h" #include "Application/Views/ModalDialogs/MessageBox.h" #include "BaseClasses/ViewEvent.h" #include "Foundation/Constants/SpecialCharacters.h" @@ -191,7 +192,8 @@ void SelectProjectView::Reset() { topIndex_ = 0; currentIndex_ = 0; selection_[0] = '\0'; - fileIndexList_.clear(); + auto fileIndexList = MemoryPool::getFileIndexList(this); + fileIndexList->clear(); } void SelectProjectView::DrawView() { @@ -217,8 +219,10 @@ void SelectProjectView::DrawView() { etl::string projectName = var->GetString(); const char *currentProject = projectName.c_str(); + auto fileIndexList = MemoryPool::getFileIndexList(this); + for (size_t i = topIndex_; - i < topIndex_ + LIST_PAGE_SIZE && (i < fileIndexList_.size()); i++) { + i < topIndex_ + LIST_PAGE_SIZE && (i < fileIndexList->size()); i++) { if (i == currentIndex_) { SetColor(CD_HILITE2); props.invert_ = true; @@ -229,7 +233,7 @@ void SelectProjectView::DrawView() { char buffer[MAX_PROJECT_NAME_LENGTH + 1]; memset(buffer, '\0', sizeof(buffer)); - unsigned fileIndex = fileIndexList_[i]; + unsigned fileIndex = (*fileIndexList)[i]; if (fs->getFileType(fileIndex) == PFT_DIR) { fs->getFileName(fileIndex, buffer, MAX_PROJECT_NAME_LENGTH + 1); @@ -268,7 +272,8 @@ void SelectProjectView::DrawView() { }; void SelectProjectView::DrawScrollBar() { - int totalItems = fileIndexList_.size(); + auto fileIndexList = MemoryPool::getFileIndexList(this); + int totalItems = fileIndexList->size(); if (totalItems <= LIST_PAGE_SIZE) { return; // no scrollbar needed } @@ -354,6 +359,7 @@ void SelectProjectView::ProcessButtonMask(unsigned short mask, bool pressed) { } void SelectProjectView::warpToNextProject(bool goUp) { + auto fileIndexList = MemoryPool::getFileIndexList(this); if (goUp) { if (currentIndex_ > 0) { @@ -365,7 +371,7 @@ void SelectProjectView::warpToNextProject(bool goUp) { } } } else { - if (currentIndex_ < fileIndexList_.size() - 1) { + if (currentIndex_ < fileIndexList->size() - 1) { currentIndex_++; // if we have scrolled off the bottom, page the file list down if not // at end of the list @@ -378,17 +384,18 @@ void SelectProjectView::warpToNextProject(bool goUp) { } void SelectProjectView::setCurrentFolder() { + auto fileIndexList = MemoryPool::getFileIndexList(this); auto fs = FileSystem::GetInstance(); fs->chdir(PROJECTS_DIR); // get ready - fileIndexList_.clear(); + fileIndexList->clear(); // Let's read all the directory in the project dir - fs->list(&fileIndexList_, "", true); + fs->list(&(*fileIndexList), "", true); // Filter out "." and ".." along with the hidden default project entry - for (auto it = fileIndexList_.begin(); it != fileIndexList_.end();) { + for (auto it = fileIndexList->begin(); it != fileIndexList->end();) { fs->getFileName(*it, selection_, MAX_PROJECT_NAME_LENGTH + 1); const bool isDotEntry = @@ -398,16 +405,16 @@ void SelectProjectView::setCurrentFolder() { if (isDotEntry || isUntitled) { if (isUntitled) { Trace::Log("SELECTPROJECTVIEW", "skipping untitled project on Index:%d", - static_cast(it - fileIndexList_.begin())); + static_cast(it - fileIndexList->begin())); } - it = fileIndexList_.erase(it); + it = fileIndexList->erase(it); } else { ++it; } } // reset & redraw screen - currentIndex_ = std::min(currentIndex_, fileIndexList_.size() - 1); + currentIndex_ = std::min(currentIndex_, fileIndexList->size() - 1); topIndex_ = 0; currentIndex_ = 0; isDirty_ = true; @@ -418,13 +425,15 @@ void SelectProjectView::getSelectedProjectName(char *name) { } void SelectProjectView::getHighlightedProjectName(char *name) { + auto fileIndexList = MemoryPool::getFileIndexList(this); name[0] = '\0'; - if (currentIndex_ >= fileIndexList_.size()) { + + if (currentIndex_ >= fileIndexList->size()) { return; } auto fs = FileSystem::GetInstance(); - unsigned fileIndex = fileIndexList_[currentIndex_]; + unsigned fileIndex = (*fileIndexList)[currentIndex_]; fs->getFileName(fileIndex, name, MAX_PROJECT_NAME_LENGTH + 1); } @@ -434,12 +443,14 @@ void SelectProjectView::SelectButton(int direction) { } void SelectProjectView::LoadProject() { - if (currentIndex_ >= fileIndexList_.size()) { + auto fileIndexList = MemoryPool::getFileIndexList(this); + + if (currentIndex_ >= fileIndexList->size()) { return; } // all subdirs directly inside /project are expected to be projects - unsigned fileIndex = fileIndexList_[currentIndex_]; + unsigned fileIndex = (*fileIndexList)[currentIndex_]; auto fs = FileSystem::GetInstance(); fs->getFileName(fileIndex, selection_, MAX_PROJECT_NAME_LENGTH + 1); if (strlen(selection_) == 0) { @@ -476,7 +487,9 @@ bool SelectProjectView::SelectionIsCurrentProject() { } void SelectProjectView::AttemptDeletingSelectedProject() { - if (currentIndex_ >= fileIndexList_.size()) { + auto fileIndexList = MemoryPool::getFileIndexList(this); + + if (currentIndex_ >= fileIndexList->size()) { return; } diff --git a/sources/Application/Views/SelectProjectView.h b/sources/Application/Views/SelectProjectView.h index 2d75bb6e6..da45604e1 100644 --- a/sources/Application/Views/SelectProjectView.h +++ b/sources/Application/Views/SelectProjectView.h @@ -39,7 +39,6 @@ class SelectProjectView : public ScreenView { size_t topIndex_ = 0; size_t currentIndex_ = 0; char selection_[MAX_PROJECT_NAME_LENGTH + 1]; - etl::vector fileIndexList_; int selectedButton_ = 0; void DrawScrollBar(); diff --git a/sources/Application/Views/ThemeImportView.cpp b/sources/Application/Views/ThemeImportView.cpp index 4d411f6e3..0a9e688d8 100644 --- a/sources/Application/Views/ThemeImportView.cpp +++ b/sources/Application/Views/ThemeImportView.cpp @@ -11,6 +11,7 @@ #include "Application/AppWindow.h" #include "Application/Model/Config.h" #include "Application/Persistency/PersistenceConstants.h" +#include "Application/Utils/MemoryPool.h" #include "Application/Views/ModalDialogs/MessageBox.h" #include "ModalDialogs/MessageBox.h" #include "System/Console/Trace.h" @@ -30,19 +31,22 @@ ThemeImportView::~ThemeImportView() {} void ThemeImportView::Reset() { topIndex_ = 0; currentIndex_ = 0; - fileIndexList_.clear(); + auto fileIndexList = MemoryPool::getFileIndexList(this); + (*fileIndexList).clear(); } void ThemeImportView::ProcessButtonMask(unsigned short mask, bool pressed) { if (!pressed) return; + auto fileIndexList = MemoryPool::getFileIndexList(this); + if (mask & EPBM_PLAY) { auto fs = FileSystem::GetInstance(); char name[PFILENAME_SIZE]; - if (currentIndex_ < fileIndexList_.size()) { - unsigned fileIndex = fileIndexList_[currentIndex_]; + if (currentIndex_ < (*fileIndexList).size()) { + unsigned fileIndex = (*fileIndexList)[currentIndex_]; fs->getFileName(fileIndex, name, PFILENAME_SIZE); if (mask & EPBM_ALT) { @@ -68,8 +72,8 @@ void ThemeImportView::ProcessButtonMask(unsigned short mask, bool pressed) { if (mask & EPBM_ENTER) { auto fs = FileSystem::GetInstance(); - if (currentIndex_ < fileIndexList_.size()) { - unsigned fileIndex = fileIndexList_[currentIndex_]; + if (currentIndex_ < (*fileIndexList).size()) { + unsigned fileIndex = (*fileIndexList)[currentIndex_]; char name[PFILENAME_SIZE]; fs->getFileName(fileIndex, name, PFILENAME_SIZE); @@ -111,8 +115,10 @@ void ThemeImportView::DrawView() { // need to use fullsize buffer as sdfat doesnt truncate if filename longer // than buffer but instead returns empty string in buffer :-( char buffer[PFILENAME_SIZE]; + auto fileIndexList = MemoryPool::getFileIndexList(this); + for (size_t i = topIndex_; - i < topIndex_ + LIST_PAGE_SIZE && (i < fileIndexList_.size()); i++) { + i < topIndex_ + LIST_PAGE_SIZE && (i < (*fileIndexList).size()); i++) { if (i == currentIndex_) { SetColor(CD_HILITE2); props.invert_ = true; @@ -122,7 +128,7 @@ void ThemeImportView::DrawView() { } memset(buffer, '\0', sizeof(buffer)); - unsigned fileIndex = fileIndexList_[i]; + unsigned fileIndex = (*fileIndexList)[i]; fs->getFileName(fileIndex, buffer, PFILENAME_SIZE); if (fs->getFileType(fileIndex) == PFT_DIR) { @@ -153,7 +159,8 @@ void ThemeImportView::OnFocus() { } void ThemeImportView::warpToNextTheme(bool goUp) { - if (fileIndexList_.empty()) + auto fileIndexList = MemoryPool::getFileIndexList(this); + if (fileIndexList->empty()) return; if (goUp) { @@ -166,7 +173,7 @@ void ThemeImportView::warpToNextTheme(bool goUp) { } } } else { - if (currentIndex_ < fileIndexList_.size() - 1) { + if (currentIndex_ < (*fileIndexList).size() - 1) { currentIndex_++; // if we have scrolled off the bottom, page the file list down if not // at end of the list @@ -234,8 +241,9 @@ void ThemeImportView::setCurrentFolder(FileSystem *fs, const char *name) { isDirty_ = true; // Update list of file indexes in this new dir - fileIndexList_.clear(); + auto fileIndexList = MemoryPool::getFileIndexList(this); + fileIndexList->clear(); // Use false for subDirOnly to include both files and directories - fs->list(&fileIndexList_, THEME_FILE_EXTENSION, false); - Trace::Debug("loaded %d files from %s", fileIndexList_.size(), name); + fs->list(&(*fileIndexList), THEME_FILE_EXTENSION, false); + Trace::Debug("loaded %d files from %s", fileIndexList->size(), name); } diff --git a/sources/Application/Views/ThemeImportView.h b/sources/Application/Views/ThemeImportView.h index 2bb4197cb..022a7c6e4 100644 --- a/sources/Application/Views/ThemeImportView.h +++ b/sources/Application/Views/ThemeImportView.h @@ -35,6 +35,5 @@ class ThemeImportView : public ScreenView { size_t topIndex_ = 0; size_t currentIndex_ = 0; - etl::vector fileIndexList_; }; #endif