initial commit

This commit is contained in:
NeilClack
2026-08-07 14:51:41 -05:00
commit 9251b3a196
604 changed files with 464448 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
#pragma once
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
namespace radiantwave::db {
class DatabaseManager;
}
namespace radiantwave::audio {
// One entry from the audio checksums manifest.
//
// Supported line formats (in priority order):
// <filename> '<display name>' <hz> <md5> // current
// <md5> <filename> // legacy fallback
//
// hz is the actual frequency value of the track (e.g. 396), written by hand
// or by a script that has no access to the frequency-id table; 0 means
// "none / unset". The manifest author may also write the frequency id (or any
// unrecognized number): only values that resolve to a known frequency are
// honored, anything else falls back to the Hz parsed from the filename, so
// the file's own name is always the safety net.
struct AudioManifestEntry {
std::string filename;
std::string display_name;
int solfeggio_frequency_hz = 0;
std::string md5;
};
// Downloads audio assets from files.radiantwavetech.com in the background
// and keeps the database's audio_files table in sync with what is actually
// on disk.
//
// Fetches checksums.md5, compares each entry against the local file's MD5,
// and re-downloads anything that is missing or whose checksum differs.
// Files present on disk but absent from the manifest are deleted, and the
// audio_files table is reconciled on every pass (and after each individual
// download) so the settings audio list reflects live progress: a file that
// just finished downloading appears in the list immediately, and files not
// yet downloaded are not listed. The worker runs a persistent loop: if
// there is no internet at startup the status shows "Waiting for internet..."
// and a download starts automatically once connectivity returns. When all
// files verify it keeps re-checking the manifest periodically so changed
// checksums are picked up while running.
class AudioDownloader {
public:
AudioDownloader() = default;
~AudioDownloader();
AudioDownloader(const AudioDownloader&) = delete;
AudioDownloader& operator=(const AudioDownloader&) = delete;
// Spawns the background thread. Safe to call repeatedly; only one worker
// runs at a time. The manifest is reconciled against `db` on every pass.
void start(db::DatabaseManager& db);
// Signals the worker to stop and joins the thread.
void shutdown();
// Returns the current human-readable status for display (e.g. footer).
std::string statusString() const;
static constexpr const char* AUDIO_BASE_URL = "https://files.radiantwavetech.com/audio/";
static constexpr const char* MANIFEST_FILENAME = "checksums.md5";
private:
void run();
bool fetchManifest(std::vector<AudioManifestEntry>& out);
bool downloadAndVerify(const std::string& filename, const std::string& expectedMd5);
void setStatus(const std::string& msg);
void wait(std::chrono::seconds seconds);
mutable std::mutex mutex_;
std::condition_variable cv_;
std::thread worker_;
std::atomic<bool> stop_{false};
std::string status_;
db::DatabaseManager* db_ = nullptr;
};
// Parses checksums.md5 manifest text into entries. Blank lines and lines
// starting with '#' are ignored. Lines that don't match a known format are
// skipped. Returns false if no valid entries were found.
bool parseManifest(const std::string& text, std::vector<AudioManifestEntry>& out);
// Maps a frequency value in Hz to its internal solfeggio frequency id using
// the same table the color palettes are seeded from (174/285->1, 396->2,
// 417->3, 432->4, 528->5, 639->6, 741->7, 852->8, 963->9). Returns 0 for
// frequencies with no id (binaurals, AlphaWaves, OriginalAudio, ...).
int frequencyIdForHz(int hz);
// Parses the leading frequency value out of an audio filename like
// "396Hz.wav" -> 396. Requires the digits to be followed by "Hz"
// (case-insensitive); returns 0 when the name has no frequency (e.g.
// "AlphaWaves.wav", "OriginalAudio.wav").
int hzFromFilename(const std::string& filename);
// Computes the lowercase MD5 hex of a file, or an empty string on failure.
std::string computeFileMd5(const std::string& path);
} // namespace radiantwave::audio