#include "gme_backend.hpp" #include #include #include #include #include "file_backend.hpp" #include #include #include #include #include #include #include #include void GmeBackend::load(const char *filename) { memset(&spec, 0, sizeof(spec)); current_file = filename; spec.format = AUDIO_S16SYS; spec.samples = 100; spec.channels = 2; spec.freq = 48000; spec.size = 100 * 2 * sizeof(int16_t); gme_open_file(filename, &gme_backend, spec.freq); if (gme_backend == NULL) { throw std::exception(); } int track_count = gme_track_count(gme_backend); streams.clear(); for (int i = 0; i < track_count; i++) { gme_info_t *info; gme_track_info(gme_backend, &info, i); PlaybackStream stream; if (info->song[0] == '\0') { stream.name = fmt::format("Song {}", i); } else { stream.name = info->song; } stream.length = ((double)info->length) / 1000.0; if (stream.length < 0.0) stream.length = 0.0; stream.id = i; streams.push_back(stream); gme_free_info(info); } } extern SDL_AudioSpec obtained; void GmeBackend::switch_stream(int idx) { if (gme_backend == NULL) { throw std::exception(); } if (idx > streams.size()) { throw std::exception(); } gme_start_track(gme_backend, idx); gme_info_t *info; gme_track_info(gme_backend, &info, idx); if (info->length < 0) { info->length = 0; } uint64_t tmp = info->length; tmp *= spec.freq; tmp /= 1000; this->length = tmp; this->loop_len = info->loop_length; this->loop_start = info->intro_length; if (info->song[0] == '\0') { this->current_title = {}; } else { this->current_title = info->song; } gme_free_info(info); gme_ignore_silence(gme_backend, true); open = true; } void GmeBackend::cleanup() { gme_delete(gme_backend); gme_backend = NULL; streams.clear(); } size_t GmeBackend::render(void *buf, size_t maxlen) { if (gme_backend == NULL) return 0; const char *err; size_t sample_type_len = 4; maxlen /= sample_type_len; if (err = gme_play(gme_backend, maxlen * 2, (short*)buf)) { ERROR.writefln("Failed to play audio: %s", err); return 0; } int pos_samples = gme_tell_samples(gme_backend); int loop_end = loop_len + loop_start; uint64_t loop_end_samples = loop_end; loop_end_samples *= spec.freq; loop_end_samples /= 1000; uint64_t loop_start_samples = loop_start; loop_start_samples *= spec.freq; loop_start_samples /= 1000; if (pos_samples >= loop_end_samples || gme_track_ended(gme_backend)) { gme_seek_samples(gme_backend, loop_start_samples + (pos_samples - loop_end_samples)); } maxlen *= sample_type_len; return maxlen; } uint64_t GmeBackend::get_min_samples() { return spec.size; } std::optional GmeBackend::get_max_samples() { return get_min_samples(); } void GmeBackend::seek_samples(uint64_t position) { gme_seek_samples(gme_backend, position); } uint64_t GmeBackend::get_position_samples() { return gme_tell_samples(gme_backend); } int GmeBackend::get_stream_idx() { return streamidx; } void GmeBackend::add_licenses() { auto &license_data = get_license_data(); auto gme = LicenseData("gme", "lgpl-2.1"); LOAD_LICENSE(gme, lgpl_2_1); license_data.insert(gme); }