Zachary Hall
ae74999276
Some checks failed
Build / build-gentoo (push) Failing after 1m25s
Build / download-system-deps (push) Successful in 3m44s
Build / get-source-code (push) Successful in 6m52s
Build / build-appimage (push) Successful in 3m29s
Build / build-android (push) Failing after 2m52s
Build / build-windows (push) Failing after 6m42s
265 lines
7.4 KiB
C++
265 lines
7.4 KiB
C++
#include "util.hpp"
|
|
#include "file_backend.hpp"
|
|
#ifdef __ANDROID__
|
|
#include <SDL.h>
|
|
#endif
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include "log.hpp"
|
|
#include <fmt/core.h>
|
|
#include <fmt/format.h>
|
|
std::string _hexdump_line(uint8_t *ptr, size_t i, size_t len) {
|
|
std::string output = fmt::format("${:08x}: ", i);
|
|
for (size_t j = 0; j < len; j++) {
|
|
output += fmt::format("{:02x} ", ptr[j]);
|
|
}
|
|
size_t remainder = 8 - len;
|
|
for (size_t j = 0; j < remainder; j++) {
|
|
output += " ";
|
|
}
|
|
for (size_t j = 0; j < len; j++) {
|
|
if (ptr[j] >= ' ' && ptr[j] < 0x7F) {
|
|
output += *((char*)(ptr + j));
|
|
} else {
|
|
output += ".";
|
|
}
|
|
}
|
|
output += "\n";
|
|
return output;
|
|
}
|
|
std::string hexdump(void *ptr, size_t len) {
|
|
uint8_t *ptr8 = (uint8_t*)ptr;
|
|
size_t len_div_8 = len / 8;
|
|
size_t remainder = len % 8;
|
|
std::string output;
|
|
for (size_t i = 0; i < len_div_8; i++) {
|
|
output += _hexdump_line(ptr8 + (i * 8), i * 8, 8);
|
|
}
|
|
output += _hexdump_line(ptr8 + (len_div_8 * 8), len_div_8 * 8, remainder);
|
|
return output;
|
|
}
|
|
std::string PadZeros(std::string input, size_t required_length) {
|
|
return std::string(required_length - std::min(required_length, input.length()), '0') + input;
|
|
}
|
|
uint8_t TimeToComponentCount(double time_code) {
|
|
int seconds = (int)time_code;
|
|
int minutes = seconds / 60;
|
|
seconds -= minutes * 60;
|
|
int hours = minutes / 60;
|
|
minutes -= hours * 60;
|
|
if (hours > 0) {
|
|
return 3;
|
|
} else if (minutes > 0) {
|
|
return 2;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
std::string TimeToString(double time_code, uint8_t min_components) {
|
|
uint8_t components = std::max(TimeToComponentCount(time_code), min_components);
|
|
int seconds = (int)time_code;
|
|
int minutes = seconds / 60;
|
|
seconds -= minutes * 60;
|
|
int hours = minutes / 60;
|
|
minutes -= hours * 60;
|
|
std::string output = PadZeros(std::to_string(seconds), components < 2 ? 1 : 2);
|
|
if (components >= 2) {
|
|
output = PadZeros(std::to_string(minutes), components == 2 ? 1 : 2) + ":" + output;
|
|
}
|
|
if (components >= 3) {
|
|
output = PadZeros(std::to_string(hours), components == 3 ? 1 : 2) + ":" + output;
|
|
}
|
|
return output;
|
|
}
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <shlobj.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
std::string get_prefs_path() {
|
|
std::string path;
|
|
#ifdef __ANDROID__
|
|
path = SDL_AndroidGetInternalStoragePath();
|
|
#elif defined(_WIN32)
|
|
PWSTR str;
|
|
if (SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &str) != S_OK) {
|
|
CoTaskMemFree(str);
|
|
path = ".";
|
|
} else {
|
|
path = std::string(str);
|
|
CoTaskMemFree(str);
|
|
}
|
|
path = path + "\\";
|
|
#else
|
|
const char *str = getenv("XDG_CONFIG_HOME");
|
|
if (str == NULL) {
|
|
str = getenv("HOME");
|
|
if (str == NULL) {
|
|
path = ".";
|
|
} else {
|
|
path = std::string(str) + "/.config";
|
|
}
|
|
} else {
|
|
path = std::string(str);
|
|
}
|
|
path = path + "/";
|
|
#endif
|
|
return path;
|
|
}
|
|
int launch(std::vector<std::string> args) {
|
|
char **argv;
|
|
bool err = false;
|
|
argv = (char**)calloc(args.size() + 1, sizeof(char*));
|
|
for (size_t i = 0; i < args.size(); i++) {
|
|
argv[i] = strdup(args[i].c_str());
|
|
}
|
|
int pid = fork();
|
|
if (pid < 0) {
|
|
err = true;
|
|
} else if (pid == 0) {
|
|
execvp(argv[0], argv);
|
|
}
|
|
for (size_t i = 0; i < args.size(); i++) {
|
|
free(argv[i]);
|
|
}
|
|
free(argv);
|
|
if (err) {
|
|
throw std::exception();
|
|
}
|
|
return pid;
|
|
}
|
|
extern char *executable_path;
|
|
|
|
int launch_self(std::string process_type, std::vector<std::string> extra_args) {
|
|
extra_args.push_back(fmt::format("--process-type={0}", process_type));
|
|
extra_args.insert(extra_args.cbegin(), executable_path);
|
|
extra_args.push_back(fmt::format("--log-level={0}", Looper::Log::LogStream::log_level));
|
|
return launch(extra_args);
|
|
}
|
|
fs::path get_base_dir() {
|
|
auto path = fs::path(executable_path);
|
|
return path.parent_path();
|
|
}
|
|
void blocking_write(int fd, const void *buf, const size_t len) {
|
|
ssize_t tmp;
|
|
size_t i = 0;
|
|
while (i < len) {
|
|
tmp = write(fd, ((uint8_t*)buf) + i, len - i);
|
|
if (tmp < 0) {
|
|
throw CustomException("Failed to write to fd!");
|
|
}
|
|
i += tmp;
|
|
}
|
|
assert(i == len);
|
|
}
|
|
void blocking_read(int fd, void *buf, const size_t len) {
|
|
ssize_t tmp;
|
|
size_t i = 0;
|
|
while (i < len) {
|
|
tmp = read(fd, ((uint8_t*)buf) + i, len - i);
|
|
if (tmp < 0) {
|
|
throw CustomException("Failed to read from fd!");
|
|
}
|
|
i += tmp;
|
|
}
|
|
assert(i == len);
|
|
}
|
|
|
|
int NotSDL_ConvertAudioSamples(const SDL_AudioSpec *src_spec, const Uint8 *src_data, int src_len,
|
|
const SDL_AudioSpec *dst_spec, Uint8 **dst_data, int *dst_len)
|
|
{
|
|
if (dst_data) {
|
|
*dst_data = NULL;
|
|
}
|
|
|
|
if (dst_len) {
|
|
*dst_len = 0;
|
|
}
|
|
|
|
if (!src_data) {
|
|
return 0;
|
|
} else if (src_len < 0) {
|
|
return 0;
|
|
} else if (!dst_data) {
|
|
return 0;
|
|
} else if (!dst_len) {
|
|
return 0;
|
|
}
|
|
|
|
int retval = -1;
|
|
Uint8 *dst = NULL;
|
|
int dstlen = 0;
|
|
|
|
SDL_AudioStream *stream = SDL_NewAudioStream(src_spec->format, src_spec->channels, src_spec->freq, dst_spec->format, dst_spec->channels, dst_spec->freq);
|
|
if (stream) {
|
|
SDL_AudioStreamPut(stream, src_data, src_len);
|
|
SDL_AudioStreamFlush(stream);
|
|
dstlen = SDL_AudioStreamAvailable(stream);
|
|
if (dstlen >= 0) {
|
|
dst = (Uint8 *)SDL_malloc(dstlen);
|
|
if (dst) {
|
|
retval = (SDL_AudioStreamGet(stream, dst, dstlen) >= 0) ? 0 : -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
*dst_data = dst;
|
|
*dst_len = dstlen;
|
|
|
|
SDL_FreeAudioStream(stream);
|
|
return retval;
|
|
}
|
|
PropertyHint make_hint(double min, double max) {
|
|
PropertyHint output;
|
|
auto range = output.mutable_range();
|
|
range->set_min(min);
|
|
range->set_max(max);
|
|
return output;
|
|
}
|
|
Property make_property(PropertyType type, std::string name, PropertyId id, std::optional<std::string> path, std::optional<PropertyHint> hint) {
|
|
Property output;
|
|
output.set_id(id);
|
|
output.set_name(name);
|
|
output.set_type(type);
|
|
if (path.has_value()) output.set_path(path.value());
|
|
if (hint.has_value()) output.mutable_hint()->CopyFrom(hint.value());
|
|
return output;
|
|
}
|
|
Property make_property(PropertyType type, std::string name, std::string path, std::optional<PropertyHint> hint) {
|
|
return make_property(type, name, PropertyId::BackendSpecific, path, hint);
|
|
}
|
|
Property make_property(PropertyType type, std::string name, PropertyId id, std::optional<PropertyHint> hint) {
|
|
return make_property(type, name, id, {}, hint);
|
|
|
|
}
|
|
PropertyHint make_hint(std::optional<double> min = {}, std::optional<double> max = {}) {
|
|
PropertyHint output;
|
|
PropertyHintRange &range = *output.mutable_range();
|
|
if (min.has_value()) {
|
|
range.set_min(min.value());
|
|
}
|
|
if (max.has_value()) {
|
|
range.set_max(max.value());
|
|
}
|
|
return output;
|
|
}
|
|
|
|
LooperLogScaler::LooperLogScaler(double min, double max) {
|
|
update_min_max(min, max);
|
|
}
|
|
void LooperLogScaler::update_min_max(double min, double max) {
|
|
x0 = min;
|
|
x1 = (max - min) / (exp(1.0) - 1.0);
|
|
la = min;
|
|
lb = (max - min);
|
|
// x0 = scale_log(min);
|
|
// x1 = scale_log(max);
|
|
}
|
|
double LooperLogScaler::scale_log(double value) {
|
|
return (std::log(((value - x0) / x1) + 1.0) * lb) + la;
|
|
}
|
|
double LooperLogScaler::unscale_log(double value) {
|
|
return ((std::exp((value - la) / lb) - 1.0) * x1) + x0;
|
|
}
|