v1.2.38 Fix for locale issues on non-en-US locales.

This commit is contained in:
Robin Davies
2024-08-19 00:27:28 -04:00
parent 6358682eb1
commit fa3d8815cd
16 changed files with 194 additions and 64 deletions
+2 -2
View File
@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.16.0) cmake_minimum_required(VERSION 3.16.0)
project(pipedal project(pipedal
VERSION 1.2.37 VERSION 1.2.38
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
HOMEPAGE_URL "https://rerdavies.github.io/pipedal" HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
) )
set (DISPLAY_VERSION "v1.2.37beta4") set (DISPLAY_VERSION "v1.2.38beta5")
set (CMAKE_INSTALL_PREFIX "/usr/") set (CMAKE_INSTALL_PREFIX "/usr/")
+2 -2
View File
@@ -6,11 +6,11 @@
<a href="https://rerdavies.github.io/pipedal/LicensePiPedal.html"><img src="https://img.shields.io/badge/MIT-MIT?label=license&color=%23808080"/></a> <a href="https://rerdavies.github.io/pipedal/LicensePiPedal.html"><img src="https://img.shields.io/badge/MIT-MIT?label=license&color=%23808080"/></a>
<a href="https://github.com/rerdavies/pipedal/actions"><img src="https://img.shields.io/github/actions/workflow/status/rerdavies/pipedal/cmake.yml?branch=main"/></a> <a href="https://github.com/rerdavies/pipedal/actions"><img src="https://img.shields.io/github/actions/workflow/status/rerdavies/pipedal/cmake.yml?branch=main"/></a>
Download:&nbsp;<a href='https://rerdavies.github.io/pipedal/download.html'>v1.2.37 Beta4</a>&nbsp;&nbsp;&nbsp;&nbsp; Website:&nbsp;[https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). Download:&nbsp;<a href='https://rerdavies.github.io/pipedal/download.html'>v1.2.38 Beta5</a>&nbsp;&nbsp;&nbsp;&nbsp; Website:&nbsp;[https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
&nbsp; &nbsp;
#### NEW version 1.2.37 Beta4 release, providing support for Raspberry Pi OS Bookworm. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. #### NEW version 1.2.38 Beta5 release, providing support for Raspberry Pi OS Bookworm. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
&nbsp; &nbsp;
+1 -1
View File
@@ -26,7 +26,7 @@ Run the following commands to install dependent libraries required by the PiPeda
sudo apt install -y libasound2-dev jackd2 uuid-dev libxrandr-dev sudo apt install -y libasound2-dev jackd2 uuid-dev libxrandr-dev
sudo apt install -y authbind sudo apt install -y authbind
sudo apt install -y libavahi-client-dev sudo apt install -y libavahi-client-dev
sudo apt install -y libnm-dev sudo apt install -y libnm-dev libicu-dev
sudo apt install -y libsdbus-c++-dev libzip-dev sudo apt install -y libsdbus-c++-dev libzip-dev
+3 -3
View File
@@ -13,17 +13,17 @@ page_icon: img/Install4.jpg
Download the most recent Debian (.deb) package for your platform: Download the most recent Debian (.deb) package for your platform:
- [Raspberry Pi OS bookworm (64-bit) v1.2.37 Beta4](https://github.com/rerdavies/pipedal/releases/download/) - [Raspberry Pi OS bookworm (64-bit) v1.2.38 Beta5](https://github.com/rerdavies/pipedal/releases/download/)
- [Ubuntu/Raspberry Pi OS bullseyeye (64-bit) v1.2.31](https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb) - [Ubuntu/Raspberry Pi OS bullseyeye (64-bit) v1.2.31](https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb)
Version 1.2.37 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31. Version 1.2.38 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31.
Install the package by running Install the package by running
``` ```
sudo apt update sudo apt update
cd ~/Downloads cd ~/Downloads
sudo apt-get install pipedal_1.2.37_arm64.deb sudo apt-get install pipedal_1.2.38_arm64.deb
``` ```
Adjust accordingly if you have downloaded v1.1.31. Adjust accordingly if you have downloaded v1.1.31.
+5
View File
@@ -1,4 +1,9 @@
# Release Notes # Release Notes
## Pipedal 1.2.38 Beta5
Fixes:
- PiPedal won't run on non-en-US locales.
## Pipedal 1.2.37 Beta4 ## Pipedal 1.2.37 Beta4
You can now upload GuitarML Proteus models from the GuitarML project into TooB ML. You can now upload GuitarML Proteus models from the GuitarML project into TooB ML.
+3 -3
View File
@@ -4,17 +4,17 @@
Download the most recent Debian (.deb) package for your platform: Download the most recent Debian (.deb) package for your platform:
- <a href="https://github.com/rerdavies/pipedal/releases/download/v1.2.37/pipedal_1.2.37_arm64.deb">Raspberry Pi OS Bookworm (64-bit) v1.2.37 Beta4</a> - <a href="https://github.com/rerdavies/pipedal/releases/download/v1.2.38/pipedal_1.2.38_arm64.deb">Raspberry Pi OS Bookworm (64-bit) v1.2.38 Beta5</a>
- <a href="https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb">Ubuntu 21.04 or Raspberry Pi OS bullseyeyeye (64-bit) v1.1.31</a> - <a href="https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb">Ubuntu 21.04 or Raspberry Pi OS bullseyeyeye (64-bit) v1.1.31</a>
v1.2.37 Beta4 is does not currently support Ubuntu 21.04, or older versions of Raspberry Pi OS. v1.2.38 Beta5 is does not currently support Ubuntu 21.04, or older versions of Raspberry Pi OS.
Install the package by running Install the package by running
``` ```
sudo apt update sudo apt update
cd ~/Downloads cd ~/Downloads
sudo apt-get install ./pipedal_1.2.37_arm64.deb sudo apt-get install ./pipedal_1.2.38_arm64.deb
``` ```
Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation. Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation.
+2 -2
View File
@@ -1,13 +1,13 @@
<img src="GithubBanner.png" width="100%"/> <img src="GithubBanner.png" width="100%"/>
<a href="Installing.html"><i>v1.2.37</i></a> <a href="Installing.html"><i>v1.2.38</i></a>
&nbsp; &nbsp;
To download PiPedal, click [here](download.md). To download PiPedal, click [here](download.md).
> NEW version 1.2.37 Beta4 release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. > NEW version 1.2.38 Beta5 release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet. Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet.
+4 -1
View File
@@ -133,6 +133,7 @@ endif()
set (PIPEDAL_SOURCES set (PIPEDAL_SOURCES
WebServerConfig.cpp WebServerConfig.hpp WebServerConfig.cpp WebServerConfig.hpp
Locale.hpp Locale.cpp
Finally.hpp Finally.hpp
ZipFile.cpp ZipFile.hpp ZipFile.cpp ZipFile.hpp
TemporaryFile.cpp TemporaryFile.hpp TemporaryFile.cpp TemporaryFile.hpp
@@ -204,7 +205,6 @@ set (PIPEDAL_SOURCES
AdminClient.hpp AdminClient.cpp AdminClient.hpp AdminClient.cpp
MidiBinding.hpp MidiBinding.cpp MidiBinding.hpp MidiBinding.cpp
PiPedalMath.hpp PiPedalMath.hpp
Locale.hpp Locale.cpp
Lv2EventBufferWriter.hpp Lv2EventBufferWriter.cpp Lv2EventBufferWriter.hpp Lv2EventBufferWriter.cpp
IpSubnet.hpp IpSubnet.hpp
PiPedalAlsa.hpp PiPedalAlsa.cpp PiPedalAlsa.hpp PiPedalAlsa.cpp
@@ -235,6 +235,9 @@ set (PIPEDAL_INCLUDES
) )
set(PIPEDAL_LIBS libpipedald zip set(PIPEDAL_LIBS libpipedald zip
icui18n
icuuc
icudata
pthread atomic stdc++fs asound avahi-common avahi-client systemd pthread atomic stdc++fs asound avahi-common avahi-client systemd
${VST3_LIBRARIES} ${VST3_LIBRARIES}
${LILV_0_LIBRARIES} ${LILV_0_LIBRARIES}
-1
View File
@@ -607,7 +607,6 @@ void SetVarPermissions(
if (fs::is_directory(path)) { if (fs::is_directory(path)) {
fs::permissions(path, directoryPermissions, fs::perm_options::replace); fs::permissions(path, directoryPermissions, fs::perm_options::replace);
for (const auto& entry : fs::recursive_directory_iterator(path)) { for (const auto& entry : fs::recursive_directory_iterator(path)) {
cout << " " << entry.path() << endl;
if (chown(entry.path().c_str(),uid,gid) != 0) if (chown(entry.path().c_str(),uid,gid) != 0)
{ {
+117 -26
View File
@@ -23,43 +23,134 @@
#include <stdlib.h> #include <stdlib.h>
#include "Lv2Log.hpp" #include "Lv2Log.hpp"
#include <unicode/utypes.h>
#include <unicode/ucol.h>
#include <unicode/unistr.h>
#include <unicode/sortkey.h>
#include <stdexcept>
#include "ss.hpp"
#include <mutex>
// Must be UNICODE. Should reflect system locale. (.e.g en-US.UTF8, de-de.UTF8) // Must be UNICODE. Should reflect system locale. (.e.g en-US.UTF8, de-de.UTF8)
// This is correct for libstdc++; most probably not correct for Windows or CLANG. :-( // This is correct for libstdc++; most probably not correct for Windows or CLANG. :-(
using namespace pipedal; using namespace pipedal;
static const char*getLocale(const char*localeEnvironmentVariable)
std::string getCurrentLocale() {
std::string locale = setlocale(LC_ALL, nullptr);
if (locale.empty() || locale == "C") {
// If setlocale fails, try getting it from environment variables
const char* lang = getenv("LC_ALL");
if (lang) {
locale = lang;
} else {
// If LANG is not set, fall back to a default
lang = getenv("LC_COLLATE");
if (lang)
{
locale = lang;
} else{
lang = getenv("LANG");
if (lang) {
locale = lang;
} else {
locale = "en_US";
}
}
}
}
// Extract just the language and country code
size_t dot_pos = locale.find('.');
if (dot_pos != std::string::npos) {
locale = locale.substr(0, dot_pos);
}
return locale;
}
Collator::~Collator() {
}
class LocaleImpl;
class CollatorImpl : public Collator {
public:
CollatorImpl(std::shared_ptr<LocaleImpl> LocaleImpl,icu::Locale &locale);
~CollatorImpl();
virtual int Compare(const std::string &left, const std::string&right);
private:
icu::Collator* collator = nullptr;
std::shared_ptr<LocaleImpl> localeImpl;
};
CollatorImpl::~CollatorImpl()
{ {
const char*result = getenv(localeEnvironmentVariable); delete collator;
if (result == nullptr) localeImpl = nullptr;
{ }
result = getenv("LC_ALL"); CollatorImpl::CollatorImpl(std::shared_ptr<LocaleImpl> localeImpl, icu::Locale &locale)
} :localeImpl(localeImpl)
{
UErrorCode status = U_ZERO_ERROR;
if (result == nullptr) { this->collator = icu::Collator::createInstance(locale, status);
result = "en_US.UTF-8";
if (U_FAILURE(status)) {
throw std::runtime_error(SS("Failed to create collator: " << u_errorName(status)));
} }
std::stringstream s; }
s << "Locale: " << result;
Lv2Log::error(s.str()); int CollatorImpl::Compare(const std::string &left, const std::string&right) {
return result; return collator->compare(left.c_str(),right.c_str());
}
Locale::ptr g_instance;
class LocaleImpl: public Locale, public std::enable_shared_from_this<LocaleImpl> {
public:
LocaleImpl();
virtual const std::string &CurrentLocale() const ;
virtual Collator::ptr GetCollator();
private:
std::unique_ptr<icu::Locale> locale;
std::string currentLocale;
};
LocaleImpl::LocaleImpl()
{
currentLocale = getCurrentLocale();
locale = std::make_unique<icu::Locale>(currentLocale.c_str());
}
const std::string &LocaleImpl::CurrentLocale() const
{
return currentLocale;
} }
void Locale::setDefaultLocale() { Collator::ptr LocaleImpl::GetCollator(){
const char* locale = getLocale("LC_ALL"); auto pThis = shared_from_this();
try { return std::shared_ptr<Collator>(new CollatorImpl(pThis,*locale));
setlocale(LC_ALL,locale);
} catch (const std::exception&)
{
std::stringstream s;
s << "Failed to set default locale (" << locale << "). Defaulting to en_US.";
Lv2Log::error(s.str());
std::setlocale(LC_ALL,"en_US.UTF-8");
}
} }
const std::collate<char>& Locale::collation() { return std::use_facet<std::collate<char> >(std::locale()); }
static std::mutex createMutex;
Locale::~Locale()
{
}
Locale::ptr Locale::g_instance;
Locale::ptr Locale::GetInstance()
{
std::lock_guard lock { createMutex};
if (g_instance)
{
return g_instance;
}
g_instance = std::make_shared<LocaleImpl>();
return g_instance;
}
+25 -5
View File
@@ -19,14 +19,34 @@
#pragma once #pragma once
#include <locale> #include <memory>
#include <string>
namespace pipedal { namespace pipedal {
class Collator {
class Locale {
public: public:
static void setDefaultLocale(); using ptr = std::shared_ptr<Collator>;
virtual int Compare(const std::string &left, const std::string&right) = 0;
virtual ~Collator();
};
class Locale {
protected:
Locale() { }
public:
virtual ~Locale();
// no copy, no move
Locale(const Locale&) = delete;
Locale(Locale&&) = delete;
Locale&operator =(const Locale&) = delete;
Locale&operator =(Locale&&) = delete;
using ptr = std::shared_ptr<Locale>;
static const std::collate<char>& collation(); static ptr GetInstance();
virtual const std::string &CurrentLocale() const = 0;
virtual Collator::ptr GetCollator() = 0;
private:
static ptr g_instance;
}; };
} }
+6 -6
View File
@@ -21,7 +21,7 @@
#include "PluginHost.hpp" #include "PluginHost.hpp"
#include <lilv/lilv.h> #include <lilv/lilv.h>
#include <stdexcept> #include <stdexcept>
#include <locale> #include "Locale.hpp"
#include <string_view> #include <string_view>
#include "Lv2Log.hpp" #include "Lv2Log.hpp"
#include <functional> #include <functional>
@@ -461,16 +461,16 @@ void PluginHost::Load(const char *lv2Path)
Lv2Log::info("lilv: " + s); Lv2Log::info("lilv: " + s);
} }
const auto &collation = std::use_facet<std::collate<char>>(std::locale()); auto collator = Locale::GetInstance()->GetCollator();
auto compare = [&collation]( auto compare = [&collator](
const std::shared_ptr<Lv2PluginInfo> &left, const std::shared_ptr<Lv2PluginInfo> &left,
const std::shared_ptr<Lv2PluginInfo> &right) const std::shared_ptr<Lv2PluginInfo> &right)
{ {
const char *pb1 = left->name().c_str(); const char *pb1 = left->name().c_str();
const char *pb2 = right->name().c_str(); const char *pb2 = right->name().c_str();
return collation.compare( return collator->Compare(
pb1, pb1 + left->name().size(), left->name(),right->name())
pb2, pb2 + right->name().size()) < 0; < 0;
}; };
std::sort(this->plugins_.begin(), this->plugins_.end(), compare); std::sort(this->plugins_.begin(), this->plugins_.end(), compare);
+11 -7
View File
@@ -18,6 +18,7 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "pch.h" #include "pch.h"
#include "Locale.hpp"
#include "Storage.hpp" #include "Storage.hpp"
#include "AudioConfig.hpp" #include "AudioConfig.hpp"
#include "PiPedalException.hpp" #include "PiPedalException.hpp"
@@ -40,7 +41,6 @@ const char *BANKS_FILENAME = "index.banks";
#define USER_SETTINGS_FILENAME "userSettings.json"; #define USER_SETTINGS_FILENAME "userSettings.json";
Storage::Storage() Storage::Storage()
: locale("en_US.UTF-8")
{ {
SetConfigRoot("~/var/Config"); SetConfigRoot("~/var/Config");
SetDataRoot("~/var/PiPedal"); SetDataRoot("~/var/PiPedal");
@@ -1525,9 +1525,10 @@ std::vector<std::string> Storage::GetFileList(const UiFileProperty &fileProperty
} }
// sort lexicographically // sort lexicographically
auto collator = Locale::GetInstance()->GetCollator();
std::sort(result.begin(), result.end(), [this](const std::string&left,const std::string&right) { std::sort(result.begin(), result.end(), [&collator](const std::string&left,const std::string&right) {
return this->locale(left,right) < 0; return collator->Compare(left,right) < 0;
}); });
return result; return result;
} }
@@ -1606,12 +1607,14 @@ std::vector<FileEntry> Storage::GetFileList2(const std::string &relativePath,con
// sort lexicographically // sort lexicographically
std::sort(result.begin(), result.end(),[this](const FileEntry&l, const FileEntry&r) { auto collator = Locale::GetInstance()->GetCollator();
std::sort(result.begin(), result.end(),[&collator](const FileEntry&l, const FileEntry&r) {
if (l.isDirectory_ != r.isDirectory_) if (l.isDirectory_ != r.isDirectory_)
{ {
return l.isDirectory_ > r.isDirectory_; return l.isDirectory_ > r.isDirectory_;
} }
return this->locale(l.filename_,r.filename_); return collator->Compare(l.filename_,r.filename_) < 0;
}); });
return result; return result;
@@ -1813,10 +1816,11 @@ void Storage::FillSampleDirectoryTree(FilePropertyDirectoryTree*node, const std:
node->children_.push_back(std::move(childTree)); node->children_.push_back(std::move(childTree));
} }
} }
auto collator = Locale::GetInstance()->GetCollator();
std::sort(node->children_.begin(),node->children_.end(), std::sort(node->children_.begin(),node->children_.end(),
[this](const FilePropertyDirectoryTree::ptr&left,const FilePropertyDirectoryTree::ptr&right) [&collator](const FilePropertyDirectoryTree::ptr&left,const FilePropertyDirectoryTree::ptr&right)
{ {
return this->locale(left->directoryName_,right->directoryName_); return collator->Compare(left->directoryName_,right->directoryName_) < 0;
}); });
} }
FilePropertyDirectoryTree::ptr Storage::GetFilePropertydirectoryTree(const UiFileProperty&uiFileProperty) const FilePropertyDirectoryTree::ptr Storage::GetFilePropertydirectoryTree(const UiFileProperty&uiFileProperty) const
-2
View File
@@ -30,7 +30,6 @@
#include "WifiDirectConfigSettings.hpp" #include "WifiDirectConfigSettings.hpp"
#include "FileEntry.hpp" #include "FileEntry.hpp"
#include <map> #include <map>
#include <locale>
#include "FilePropertyDirectoryTree.hpp" #include "FilePropertyDirectoryTree.hpp"
@@ -67,7 +66,6 @@ struct PluginPresetValues {
class Storage { class Storage {
private: private:
std::locale locale;
std::filesystem::path dataRoot; std::filesystem::path dataRoot;
std::filesystem::path configRoot; std::filesystem::path configRoot;
BankIndex bankIndex; BankIndex bankIndex;
+12 -1
View File
@@ -19,7 +19,7 @@
#include "pch.h" #include "pch.h"
#include "util.hpp" #include "util.hpp"
#include "Locale.hpp"
#include "AudioConfig.hpp" #include "AudioConfig.hpp"
#include "WebServer.hpp" #include "WebServer.hpp"
#include <iostream> #include <iostream>
@@ -230,6 +230,17 @@ int main(int argc, char *argv[])
try try
{ {
{
auto locale = Locale::GetInstance();
Lv2Log::info(SS("Locale: " << locale->CurrentLocale()));
try {
auto collator = locale->GetCollator();
} catch (std::exception&e)
{
Lv2Log::error(e.what());
return EXIT_SUCCESS; //tell systemd not to auto-restart.
}
}
PiPedalModel model; PiPedalModel model;
model.Init(configuration); model.Init(configuration);
+1 -2
View File
@@ -1,4 +1,4 @@
- Zip file upload in a subdirectory. - Bug: text Cursor hovering over the breadcrumb bar in file property dialog.
- Turning off wifi-direct sould re-enable NetworkManager. - Turning off wifi-direct sould re-enable NetworkManager.
- ToobML save/restore state. - ToobML save/restore state.
@@ -16,6 +16,5 @@
Pri Description Pri Description
----------------- -----------------
9 Upload proteus patches.
8 Migrate to Vite toolchain. 8 Migrate to Vite toolchain.
5 Re-use plugin instances when rebuilding pedalboard. 5 Re-use plugin instances when rebuilding pedalboard.