Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sources/Adapters/adv/filesystem/advFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ PicoFileType advFileSystem::getFileType(int index) {
}

void advFileSystem::list(etl::ivector<int> *fileIndexes, const char *filter,
bool subDirOnly, bool includeHidden) {
bool subDirOnly, bool includeHidden, bool sorted) {

fileIndexes->clear();

Expand Down
3 changes: 2 additions & 1 deletion sources/Adapters/adv/filesystem/advFileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class advFileSystem : public FileSystem {
virtual FileHandle Open(const char *name, const char *mode) override;
virtual bool chdir(const char *path) override;
virtual void list(etl::ivector<int> *fileIndexes, const char *filter,
bool subDirOnly, bool includeHidden = false) override;
bool subDirOnly, bool includeHidden = false,
bool sorted = false) override;
virtual void getFileName(int index, char *name, int length) override;
virtual PicoFileType getFileType(int index) override;
virtual bool isParentRoot() override;
Expand Down
2 changes: 1 addition & 1 deletion sources/Adapters/adv/gui/SerialDebugUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ void SerialDebugUI::listFiles(const char *path) {
Trace::Error("failed to ls files path:%s", path);
}
etl::vector<int, MAX_FILE_INDEX_SIZE> fileIndexes;
fs->list(&fileIndexes, "", false);
fs->list(&fileIndexes, "", false, true, true);

// 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
Expand Down
107 changes: 94 additions & 13 deletions sources/Adapters/picoTracker/filesystem/picoTrackerFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
*/

#include "picoTrackerFileSystem.h"
#include "Application/Persistency/PersistenceConstants.h"
#include "Externals/etl/include/etl/pool.h"
#include "Foundation/Services/MemoryService.h"
#include "pico/multicore.h"
#include <cstring>

Expand All @@ -18,6 +20,38 @@ constexpr uint32_t MAX_OPEN_FILES = 10;

static etl::pool<picoTrackerFile, MAX_OPEN_FILES> filePool;

// compile-time generated map to change uppercase letters to lowercase for
// sorting, leave all other characters unchanged. could be used to also change
// the sort order for other/special characters if needed
static constexpr uint8_t getCharacterSortRank(uint8_t value) {
return (value >= 'A' && value <= 'Z') ? 'a' + (value - 'A') : value;
}

template <size_t... Indexes>
constexpr std::array<uint8_t, sizeof...(Indexes)>
MakeSortMap(std::index_sequence<Indexes...>) {
return {getCharacterSortRank(static_cast<uint8_t>(Indexes))...};
}

static constexpr auto kSortMap = MakeSortMap(std::make_index_sequence<256>{});

// extracts a uint32 from the first four letters of a string for faster sorting
// by comparing these uint32 values instead of doing string compares
static uint32_t getFileSortKey(char *filename) {
uint32_t sortKey = 0;
uint8_t *value = (uint8_t *)filename;

for (size_t i = 0; i < 4; i++) {
sortKey <<= 8;
if (*value != '\0') {
sortKey |= kSortMap[*value];
value++;
}
}

return sortKey;
}

picoTrackerFileSystem::picoTrackerFileSystem() {
// init out access mutex
std::lock_guard<Mutex> lock(mutex);
Expand Down Expand Up @@ -121,9 +155,10 @@ PicoFileType picoTrackerFileSystem::getFileType(int index) {

void picoTrackerFileSystem::list(etl::ivector<int> *fileIndexes,
const char *filter, bool subDirOnly,
bool includeHidden) {
std::lock_guard<Mutex> lock(mutex);
bool includeHidden, bool sorted) {
std::unique_lock<Mutex> lock(mutex);

uint32_t sortKeys[MAX_FILE_INDEX_SIZE];
fileIndexes->clear();

File cwd;
Expand Down Expand Up @@ -158,22 +193,65 @@ void picoTrackerFileSystem::list(etl::ivector<int> *fileIndexes,
}
// filter out "." and files that dont match filter if a filter is given
if ((entry.isDirectory() && entry.dirIndex() != 0) ||
((includeHidden || !entry.isHidden()) && matchesFilter)) {
if (subDirOnly) {
if (entry.isDirectory()) {
fileIndexes->push_back(index);
}
(!entry.isHidden() && matchesFilter)) {
bool add = false;

if (subDirOnly && entry.isDirectory()) {
add = entry.isDirectory();
} else {
add = true;
}

if (add) {
fileIndexes->push_back(index);
entry.getName(buffer, PFILENAME_SIZE);
sortKeys[fileIndexes->size() - 1] = getFileSortKey(buffer);
count++;
}
// Trace::Log("FILESYSTEM", "[%d] got file: %s", index, buffer);
count++;
} else {
// Trace::Log("FILESYSTEM", "skipped hidden: %s", buffer);
}
entry.close();
}

cwd.close();
lock.unlock();

// sort using insertion sort (with an extra step if our keys are identical)
constexpr int total = MAX_PROJECT_NAME_LENGTH + 1;
char currentName[total];
char prevName[total];

for (size_t i = 1; i < count; i++) {
uint32_t key = sortKeys[i];
int index = fileIndexes->at(i);
size_t j = i;

while (j > 0) {
bool shouldMove = sortKeys[j - 1] > key;

if (!shouldMove && sortKeys[j - 1] == key) {
// keys are identical, do a tiebreaker by doing a string compare to
// ensure stable sorting of files with same first 4 letters
getFileName(index, currentName, total);
getFileName(fileIndexes->at(j - 1), prevName, total);
shouldMove = strcasecmp(prevName, currentName) > 0;
}

if (shouldMove) {
sortKeys[j] = sortKeys[j - 1];
fileIndexes->at(j) = fileIndexes->at(j - 1);
--j;
} else {
break;
}
}

sortKeys[j] = key;
fileIndexes->at(j) = index;
}

Trace::Log("FILESYSTEM", "scanned: %d, added file indexes:%d", count,
fileIndexes->size());
}
Expand Down Expand Up @@ -277,21 +355,24 @@ bool picoTrackerFileSystem::CopyFile(const char *srcFilename,
auto fSrc = sd.open(srcFilename, O_READ);
auto fDest = sd.open(destFilename, O_WRITE | O_CREAT);

int n = 0;
int bufferSize = sizeof(fileBuffer_);
unsigned int n = 0;
const int bufSize = 1024;
char buffer[bufSize];

while (true) {
n = fSrc.read(fileBuffer_, bufferSize);
n = fSrc.read(buffer, bufSize);
// check for read error and only write if no error
if (n >= 0) {
fDest.write(fileBuffer_, n);
fDest.write(buffer, n);
} else {
Trace::Error("Failed to read file: %s", srcFilename);
return false;
}
if (n < bufferSize) {
if (n < bufSize) {
break;
}
}

fSrc.close();
fDest.close();
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class picoTrackerFileSystem : public FileSystem {
virtual FileHandle Open(const char *name, const char *mode) override;
virtual bool chdir(const char *path) override;
virtual void list(etl::ivector<int> *fileIndexes, const char *filter,
bool subDirOnly, bool includeHidden = false) override;
bool subDirOnly, bool includeHidden = false,
bool sorted = false) override;
virtual void getFileName(int index, char *name, int length) override;
virtual PicoFileType getFileType(int index) override;
virtual bool isParentRoot() override;
Expand All @@ -50,9 +51,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
Expand Down
15 changes: 9 additions & 6 deletions sources/Adapters/picoTracker/gui/SerialDebugUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "SerialDebugUI.h"
#include "Application/Model/Config.h"
#include "Foundation/Services/MemoryService.h"
#include "System/FileSystem/FileSystem.h"
#include "System/FileSystem/I_File.h"
#include "hardware/uart.h"
Expand Down Expand Up @@ -134,13 +135,14 @@ void SerialDebugUI::listFiles(const char *path) {
if (!fs->chdir(path)) {
Trace::Error("failed to ls files path:%s", path);
}
etl::vector<int, MAX_FILE_INDEX_SIZE> fileIndexes;
fs->list(&fileIndexes, "", false);

etl::vector<int, MAX_FILE_INDEX_SIZE> fileIndexList;
fs->list(&fileIndexList, "", false, true, true);

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);
Expand All @@ -154,7 +156,8 @@ void SerialDebugUI::rmFile(const char *path) {
Trace::Error("failed to delete file:%s", path);
} else {
Trace::Log("SERIALDEBUGUI", "deleted file:%s", path);
char buf[128];
char buf[256];

npf_snprintf(buf, sizeof(buf), "deleted:%s\n", path);
uart_write_blocking(DEBUG_UART, (uint8_t *)buf, sizeof(buf));
}
Expand Down
2 changes: 0 additions & 2 deletions sources/Application/AppWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,6 @@ AppWindow::AppWindow(I_GUIWindowImp &imp, const char *projectName)

// Init all members

_statusLine[0] = 0;

_currentView = nullptr;
_closeProject = false;
_lastA = 0;
Expand Down
2 changes: 2 additions & 0 deletions sources/Application/AppWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ class AppWindow : public GUIWindow, I_Observer, Status {
public:
// Static accessor for the animation frame counter
static uint32_t GetAnimationFrameCounter() { return animationFrameCounter_; }

View *getCurrentView() { return _currentView; }
};

#endif
13 changes: 6 additions & 7 deletions sources/Application/Audio/AudioFileStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,12 @@ bool AudioFileStreamer::Start(const char *name, int startSample, bool looping) {
#endif

wav_.Close();
Trace::Log("", "wave open:%s", name_.c_str());
auto res = wav_.Open(name_.c_str());
if (!res) {
Trace::Error("Failed to open streaming of file:%s", name_.c_str());
mode_ = AFSM_STOPPED;
return false;
}

Trace::Log("", "wave open:%s", name);
auto res = wav_.Open(name);
Trace::Error("Failed to open streaming of file:%s", name_.c_str());
mode_ = AFSM_STOPPED;
return false;

// Get sample rate information and calculate speed factor
fileSampleRate_ = wav_.GetSampleRate(-1);
Expand Down
10 changes: 5 additions & 5 deletions sources/Application/Instruments/SamplePool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "Externals/etl/include/etl/string.h"
#include "Externals/etl/include/etl/string_stream.h"
#include "Foundation/Constants/SpecialCharacters.h"
#include "Foundation/Services/MemoryService.h"
#include "System/Console/Trace.h"
#include "System/FileSystem/FileSystem.h"
#include "System/FileSystem/I_File.h"
Expand Down Expand Up @@ -57,10 +58,9 @@ void SamplePool::Load(const char *projectName) {
PROJECT_SAMPLES_DIR);
}
// First, find all wav files
etl::vector<int, MAX_FILE_INDEX_SIZE> fileIndexes;
fs->list(&fileIndexes, ".wav", false);
fs->list(&fileIndexList_, ".wav", false, false, true);
char name[PFILENAME_SIZE];
uint totalSamples = fileIndexes.size();
uint totalSamples = fileIndexList_.size();

// store for ui updates
importCount = totalSamples;
Expand All @@ -69,8 +69,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(
Expand Down
1 change: 1 addition & 0 deletions sources/Application/Instruments/SamplePool.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class SamplePool : public T_Factory<SamplePool>, public Observable {

private:
etl::vector<I_Observer *, MAX_SAMPLEINSTRUMENT_COUNT> observers_;
etl::vector<int, MAX_FILE_INDEX_SIZE> fileIndexList_;
};

#endif
14 changes: 8 additions & 6 deletions sources/Application/Model/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "Externals/etl/include/etl/flat_map.h"
#include "Externals/etl/include/etl/string.h"
#include "Externals/etl/include/etl/string_utilities.h"
#include "Foundation/Services/MemoryService.h"
#include "Services/Midi/MidiService.h"
#include "System/Console/Trace.h"
#include "System/Console/nanoprintf.h"
Expand Down Expand Up @@ -442,24 +443,25 @@ void Config::ReadColorVariable(PersistencyDocument *doc) {
// Process the current element if it's a Color element
if (strcmp(doc->ElemName(), "Color") == 0) {
// Process Color element
char colorName[64] = {0};
char colorValue[64] = {0};
const int colorSize = 64;
char colorName[colorSize];
char colorValue[colorSize];

// Get the name and value attributes
while (doc->NextAttribute()) {
if (strcmp(doc->attrname_, "name") == 0) {
// Use safer string copy to ensure null-termination
size_t len = strlen(doc->attrval_);
if (len >= sizeof(colorName)) {
len = sizeof(colorName) - 1; // Truncate if too long
if (len >= colorSize) {
len = colorSize - 1; // Truncate if too long
}
memcpy(colorName, doc->attrval_, len);
colorName[len] = '\0'; // Ensure null-termination
} else if (strcmp(doc->attrname_, "value") == 0) {
// Use safer string copy to ensure null-termination
size_t len = strlen(doc->attrval_);
if (len >= sizeof(colorValue)) {
len = sizeof(colorValue) - 1; // Truncate if too long
if (len >= colorSize) {
len = colorSize - 1; // Truncate if too long
}
memcpy(colorValue, doc->attrval_, len);
colorValue[len] = '\0'; // Ensure null-termination
Expand Down
Loading