#include "util.hpp" #include "file_backend.hpp" #ifdef __ANDROID__ #include #endif #include #include #include #include "log.hpp" #include #include 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 #include #else #include #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 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 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 path, std::optional 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 hint) { return make_property(type, name, PropertyId::BackendSpecific, path, hint); } Property make_property(PropertyType type, std::string name, PropertyId id, std::optional hint) { return make_property(type, name, id, {}, hint); } PropertyHint make_hint(std::optional min = {}, std::optional 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; }