Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for dual OPL #6

Merged
merged 3 commits into from
Jun 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ if(${RETROWAVE_BUILD_PLAYER} EQUAL 1)
CPMAddPackage(
NAME TinyVGM
GITHUB_REPOSITORY SudoMaker/TinyVGM
VERSION 0.0.2
#VERSION v1.0.2
GIT_TAG a122a90f3ebacea7af25b92b183664dc5a3621e4
)

include_directories(${cxxopts_SOURCE_DIR}/include)
Expand Down
19 changes: 2 additions & 17 deletions Player/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@
// iconv_close(cd);
//}

void RetroWavePlayer::char16_to_string(std::string &str, int16_t *c16) {
void RetroWavePlayer::char16_to_string(std::string &str, int16_t *c16, uint32_t memsize) {
str.clear();

if (!c16)
return;

size_t c16_len = tinyvgm_strlen16(c16);
size_t c16_len = memsize / 2;

if (!c16_len)
return;
Expand All @@ -100,18 +100,3 @@ void RetroWavePlayer::char16_to_string(std::string &str, int16_t *c16) {
//
// str.resize(to_next - &str[0]);
}

void RetroWavePlayer::gd3_to_info(TinyVGMGd3Info *g) {
char16_to_string(metadata.title, g->title);
char16_to_string(metadata.album, g->album);
char16_to_string(metadata.system_name, g->system_name);
char16_to_string(metadata.composer, g->composer);
char16_to_string(metadata.release_date, g->release_date);
char16_to_string(metadata.converter, g->converter);
char16_to_string(metadata.note, g->note);

char16_to_string(metadata.title_jp, g->title_jp);
char16_to_string(metadata.album_jp, g->album_jp);
char16_to_string(metadata.system_name_jp, g->system_name_jp);
char16_to_string(metadata.composer_jp, g->composer_jp);
}
5 changes: 3 additions & 2 deletions Player/OSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@

static std::unordered_map<int, std::string_view> regmap_name = {
{0x5a, "OPL2"},
{0xaa, "OPL2 dual"},
{0x5e, "OPL3 Port0"},
{0x5f, "OPL3 Port1"},
{0x50, "SN76489"},
Expand Down Expand Up @@ -333,9 +334,9 @@ void RetroWavePlayer::osd_show() {

if (total_samples) {
auto [th, tm, ts] = sec2hms(total_samples / sample_rate);
printf("Playing: %02d:%02d:%02d / %02d:%02d:%02d +%011.6lfms (%zu/%zu %s+%05zu\033[0m %06.3lf)\033[K\n", h, m, s, th, tm, ts, last_slept_msecs, played_samples, total_samples, samples_color, last_slept_samples, fps);
printf("Playing: %02zu:%02zu:%02zu / %02zu:%02zu:%02zu +%011.6lfms (%zu/%zu %s+%05zu\033[0m %06.3lf)\033[K\n", h, m, s, th, tm, ts, last_slept_msecs, played_samples, total_samples, samples_color, last_slept_samples, fps);
} else {
printf("Playing: %02d:%02d:%02d +%011.6lfms (%zu %s+%05zu\033[0m %06.3lf)\033[K\n", h, m, s, last_slept_msecs, played_samples, samples_color, last_slept_samples, fps);
printf("Playing: %02zu:%02zu:%02zu +%011.6lfms (%zu %s+%05zu\033[0m %06.3lf)\033[K\n", h, m, s, last_slept_msecs, played_samples, samples_color, last_slept_samples, fps);
}

last_last_slept_samples = last_slept_samples;
Expand Down
218 changes: 135 additions & 83 deletions Player/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
*/

#include "Player.hpp"
#include <string.h>

RetroWavePlayer player;

Expand Down Expand Up @@ -96,52 +97,129 @@ void RetroWavePlayer::init_retrowave() {
usleep(200 * 1000);
}

void RetroWavePlayer::init_tinyvgm() {
tinyvgm_init(&tvc);

std::unordered_map<uint8_t, int (*)(void *, uint8_t, const void *, uint32_t)> cmd_cb_map = {
{0x5a, callback_opl2},
{0x5e, callback_opl3_port0},
{0x5f, callback_opl3_port1},
{0xbd, callback_saa1099},
{0x50, callback_sn76489_port0},
{0x51, callback_ym2413},
{0x30, callback_sn76489_port1},
};
static int tvc_callback_command(void *userp, unsigned int cmd, const void *buf, uint32_t cmd_val_len)
{
auto t = (RetroWavePlayer *)userp;

switch (cmd)
{
case 0x61: return RetroWavePlayer::callback_sleep (userp, cmd, buf, cmd_val_len);
case 0x62: return RetroWavePlayer::callback_sleep_62 (userp, cmd, buf, cmd_val_len);
case 0x63: return RetroWavePlayer::callback_sleep_63 (userp, cmd, buf, cmd_val_len);
case 0x70: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x71: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x72: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x73: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x74: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x75: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x76: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x77: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x78: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x79: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x7a: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x7b: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x7c: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x7d: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x7e: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
case 0x7f: return RetroWavePlayer::callback_sleep_7n (userp, cmd, buf, cmd_val_len);
}

for (auto &it : disabled_vgm_commands) {
cmd_cb_map.erase(it);
printf("info: disabled VGM command %02x\n", it);
if (t->disabled_vgm_commands.count(cmd)) return TinyVGM_OK;

switch (cmd)
{
case 0x5a: return RetroWavePlayer::callback_opl2 (userp, cmd, buf, cmd_val_len);
case 0xaa: return RetroWavePlayer::callback_opl2_dual (userp, cmd, buf, cmd_val_len);
case 0x5e: return RetroWavePlayer::callback_opl3_port0 (userp, cmd, buf, cmd_val_len);
case 0x5f: return RetroWavePlayer::callback_opl3_port1 (userp, cmd, buf, cmd_val_len);
case 0xbd: return RetroWavePlayer::callback_saa1099 (userp, cmd, buf, cmd_val_len);
case 0x50: return RetroWavePlayer::callback_sn76489_port0 (userp, cmd, buf, cmd_val_len);
case 0x51: return RetroWavePlayer::callback_ym2413 (userp, cmd, buf, cmd_val_len);
case 0x30: return RetroWavePlayer::callback_sn76489_port1 (userp, cmd, buf, cmd_val_len);
}

return TinyVGM_OK; // ignore command
}

static int tvc_callback_header(void *userp, TinyVGMHeaderField field, uint32_t value)
{
auto t = (RetroWavePlayer *)userp;

switch (field)
{
case TinyVGM_HeaderField_Total_Samples: return RetroWavePlayer::callback_header_total_samples (userp, value);
case TinyVGM_HeaderField_SN76489_Clock: return RetroWavePlayer::callback_header_sn76489 (userp, value);
case TinyVGM_HeaderField_GD3_Offset:
t->gd3_offset_abs = value + tinyvgm_headerfield_offset(field);
break;
case TinyVGM_HeaderField_Data_Offset:
t->data_offset_abs = value + tinyvgm_headerfield_offset(field);
break;
}

for (auto &it : cmd_cb_map) {
tinyvgm_add_command_callback(&tvc, it.first, it.second, this);
printf("debug: VGM cmd %02x handler %p\n", it.first, it.second);
return TinyVGM_OK; // ignore header
}

static int tvc_callback_metadata(void *userp, TinyVGMMetadataType field, uint32_t pos, uint32_t len)
{
auto t = (RetroWavePlayer *)userp;

#define X(F) t->char16_to_string(t->metadata.F, (int16_t *)(t->file_buf.data() + pos), len);

switch (field)
{
case TinyVGM_MetadataType_Title_EN: X(title); break;
case TinyVGM_MetadataType_Title: X(title_jp); break;
case TinyVGM_MetadataType_Album_EN: X(album); break;
case TinyVGM_MetadataType_Album: X(album_jp); break;
case TinyVGM_MetadataType_SystemName_EN: X(system_name); break;
case TinyVGM_MetadataType_SystemName: X(system_name_jp); break;
case TinyVGM_MetadataType_Composer_EN: X(composer); break;
case TinyVGM_MetadataType_Composer: X(composer_jp); break;
case TinyVGM_MetadataType_ReleaseDate: X(release_date); break;
case TinyVGM_MetadataType_Converter: X(converter); break;
case TinyVGM_MetadataType_Notes: X(note); break;
}

// tinyvgm_add_command_callback(&tvc, 0x5a, callback_opl2, this);
// tinyvgm_add_command_callback(&tvc, 0x5e, callback_opl3_port0, this);
// tinyvgm_add_command_callback(&tvc, 0x5f, callback_opl3_port1, this);
//
// tinyvgm_add_command_callback(&tvc, 0xbd, callback_saa1099, this);
// tinyvgm_add_command_callback(&tvc, 0x50, callback_sn76489_port0, this);
// tinyvgm_add_command_callback(&tvc, 0x51, callback_ym2413, this);
// tinyvgm_add_command_callback(&tvc, 0x30, callback_sn76489_port1, this);
#undef X
return TinyVGM_OK;
}

int32_t tvc_callback_read(void *userp, uint8_t *buf, uint32_t len)
{
auto t = (RetroWavePlayer *)userp;

tinyvgm_add_command_callback(&tvc, 0x61, callback_sleep, this);
tinyvgm_add_command_callback(&tvc, 0x62, callback_sleep_62, this);
tinyvgm_add_command_callback(&tvc, 0x63, callback_sleep_63, this);
if (t->file_pos >= t->file_buf.size())
{
return 0;
}

for (int i = 0x70; i <= 0x7f; i++) {
tinyvgm_add_command_callback(&tvc, i, callback_sleep_7n, this);
if (t->file_pos + len >= t->file_buf.size())
{
len = t->file_buf.size() - t->file_pos;
}
memcpy (buf, t->file_buf.data() + t->file_pos, len);
t->file_pos+=len;
return len;
}

tinyvgm_add_header_callback(&tvc, 0x18, callback_header_total_samples, this);
tinyvgm_add_header_callback(&tvc, 0x0c, callback_header_sn76489, this);
int tvc_callback_seek(void *userp, uint32_t pos)
{
auto t = (RetroWavePlayer *)userp;

tinyvgm_add_event_callback(&tvc, TinyVGM_Event_HeaderParseDone, callback_header_done, this);
tinyvgm_add_event_callback(&tvc, TinyVGM_Event_PlaybackDone, callback_playback_done, this);
t->file_pos = pos;

return 0;
}

void RetroWavePlayer::init_tinyvgm() {
memset (&tvc, 0, sizeof (tvc));
tvc.userp = this;
tvc.callback.header = tvc_callback_header;
tvc.callback.metadata = tvc_callback_metadata;
tvc.callback.command = tvc_callback_command;
tvc.callback.seek = tvc_callback_seek;
tvc.callback.read = tvc_callback_read;
}

void RetroWavePlayer::parse_disabled_vgm_commands(const std::string &str) {
Expand All @@ -164,6 +242,10 @@ void RetroWavePlayer::parse_disabled_vgm_commands(const std::string &str) {
}

bool RetroWavePlayer::load_file(const std::string &path) {
gd3_offset_abs = 0;
data_offset_abs = 0;
file_pos = 0;

int fd = open(path.c_str(), O_RDONLY);

if (fd < 0) {
Expand Down Expand Up @@ -278,60 +360,33 @@ void RetroWavePlayer::play(const std::vector<std::string> &file_list) {
continue;
}

int32_t rc_tv_parse, rc_gd3_parse;

rc_tv_parse = tinyvgm_parse(&tvc, file_buf.data(), 32); // GD3 offset must be within first 32 bytes

if (rc_tv_parse == 32) {
auto gd3_offset = tvc.header_info.gd3_offset;
auto gd3_size = file_buf.size() - gd3_offset;

if (gd3_offset) {
tinyvgm_init_gd3(&gd3_info);
rc_gd3_parse = tinyvgm_parse_gd3(&gd3_info, file_buf.data()+gd3_offset, gd3_size);
if (rc_gd3_parse) {
gd3_to_info(&gd3_info);
}
}
} else {
printf("TinyVGM error: failed to process file `%s', rc=%d\n", cur_file.c_str(), rc_tv_parse);
tinyvgm_reset(&tvc);
if (tinyvgm_parse_header (&tvc) != TinyVGM_OK) {
i++;
continue;
}

const size_t parse_size_hint = 32;

for (size_t j=32; j<file_buf.size(); j+=parse_size_hint) {
size_t parse_size = parse_size_hint;

if (parse_size_hint + j > file_buf.size()) {
parse_size = file_buf.size() - j;
if (gd3_offset_abs) {
if (tinyvgm_parse_metadata(&tvc, gd3_offset_abs) != TinyVGM_OK) {
// ignore errors
}
}

rc_tv_parse = tinyvgm_parse(&tvc, file_buf.data()+j, parse_size);
callback_header_done(this);
tinyvgm_parse_commands(&tvc, data_offset_abs);

if (rc_tv_parse == INT32_MIN) {
printf("TinyVGM error: failed to process file `%s', rc=%d\n", cur_file.c_str(), rc_tv_parse);
switch (key_command)
{
case PREV:
if (i)
i--;
break;
}

played_bytes += rc_tv_parse;

if (playback_done) {
case NEXT:
i++;
break;
}

if (key_command & 0x0c) {
case QUIT:
i = file_list.size();
playback_reset();
break;
}
}

if (key_command == PREV) {
if (i)
i--;
} else {
i++;
}

key_command = NONE;
Expand All @@ -343,7 +398,6 @@ void RetroWavePlayer::play(const std::vector<std::string> &file_list) {
}

void RetroWavePlayer::playback_reset() {
playback_done = false;
played_samples = 0;
last_slept_samples = 0;
last_last_slept_samples = 0;
Expand All @@ -352,9 +406,7 @@ void RetroWavePlayer::playback_reset() {
played_bytes = 0;
last_secs = 0;

metadata = Metadata();
tinyvgm_destroy_gd3(&gd3_info);
tinyvgm_reset(&tvc);
metadata = Metadata(); // reset all pointers back to NULL
reset_chips();
usleep(200 * 1000);
}
Expand Down
Loading