looper/backends/playback/vgmstream/vgmstream.cpp
2024-09-16 15:05:53 -07:00

137 lines
No EOL
3.8 KiB
C++

#include "vgmstream.hpp"
extern "C" {
#include <vgmstream.h>
#include <util.h>
#include <plugins.h>
}
#include <filesystem>
#include "file_backend.hpp"
#include <stddef.h>
#include <string.h>
void VgmStreamBackend::load(const char *filename) {
spec.format = AUDIO_S16SYS;
file = open_file(filename);
sf = get_sf_from_file(file);
if (!sf) {
throw std::exception();
}
auto *output = init_vgmstream_from_STREAMFILE(sf);
if (!output) {
throw std::exception();
}
int stream_count = output->num_streams;
close_vgmstream(output);
streams.clear();
for (int i = 0; i < stream_count; i++) {
PlaybackStream stream;
stream.id = i;
stream.length = 0;
stream.name = "";
if (!sf) {
streams.push_back(stream);
continue;
}
sf->stream_index = i;
auto *tmp = init_vgmstream_from_STREAMFILE(sf);
if (!tmp) {
streams.push_back(stream);
continue;
}
reset_vgmstream(tmp);
stream.length = (double)tmp->num_samples / (double)tmp->sample_rate;
char *buf = (char*)calloc(STREAM_NAME_SIZE + 1, 1);
strncpy(buf, tmp->stream_name, STREAM_NAME_SIZE);
if (buf[0] == '\0') {
free(buf);
buf = strdup("Unknown");
}
if (i == 0) {
char *buf2 = NULL;
const char *const DEFAULT_FORMAT_STR = "Default (%s)";
size_t buflen = snprintf(NULL, 0, DEFAULT_FORMAT_STR, buf) + 1;
buf2 = (char*)calloc(buflen, 1);
snprintf(buf2, buflen, DEFAULT_FORMAT_STR, buf);
stream.name = buf2;
free(buf2);
} else {
stream.name = buf;
}
streams.push_back(stream);
free(buf);
close_vgmstream(tmp);
}
switch_stream(0);
}
void VgmStreamBackend::switch_stream(int idx) {
if (vf == nullptr || sf == nullptr || file == nullptr) {
open = false;
return;
}
sf->stream_index = idx;
if (idx >= streams.size()) {
throw std::exception();
}
vf = init_vgmstream_from_STREAMFILE(sf);
if (!vf) {
throw std::exception();
}
vgmstream_cfg_t cfg = {0};
cfg.allow_play_forever = 1;
cfg.play_forever = 1;
vgmstream_apply_config(vf, &cfg);
spec.channels = vf->channels;
spec.freq = vf->sample_rate;
length = streams[idx].length;
const char *title_tag = vf->stream_name;
if (title_tag[0] == '\0') {
std::filesystem::path path(current_file);
current_title = path.stem().string();
} else {
char *buf = (char*)calloc(STREAM_NAME_SIZE + 1, 1);
strncpy(buf, title_tag, STREAM_NAME_SIZE);
current_title = buf;
free(buf);
}
open = true;
}
void VgmStreamBackend::cleanup() {
streams.clear();
close_vgmstream(vf);
close_streamfile(sf);
vf = nullptr;
sf = nullptr;
delete file;
file = nullptr;
open = false;
}
size_t VgmStreamBackend::render(void *buf, size_t maxlen) {
if (vf == nullptr || sf == nullptr || file == nullptr) {
open = false;
return 0;
}
maxlen /= sizeof(sample_t);
size_t new_samples = render_vgmstream((sample_t*)(buf), (int)maxlen, vf);
if (maxlen > new_samples) {
reset_vgmstream(vf);
position = 0.0;
} else {
position += (double)new_samples / (double)vf->sample_rate;
}
return new_samples * sizeof(sample_t);
}
void VgmStreamBackend::seek(double position) {
if (vf == nullptr || sf == nullptr || file == nullptr) {
open = false;
return;
}
auto pos32 = (int32_t)(position * vf->sample_rate);
seek_vgmstream(vf, pos32);
this->position = position;
}
double VgmStreamBackend::get_position() {
return position;
}
int VgmStreamBackend::get_stream_idx() {
return vf->stream_index;
}