From cbe74b26adc38a633188f07967c18a1ef639bf78 Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Sun, 20 Mar 2022 17:12:03 +1100 Subject: [PATCH] More #79 - Add S3I Adlib instrument support. Also fix SafeReader `SEEK_CUR` handling (wasn't used at all). --- src/engine/engine.cpp | 82 +++++++++++++++++++++++++++++++++++++++ src/engine/safeReader.cpp | 4 +- src/gui/gui.cpp | 5 ++- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 835636bdd..1f52ad166 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1223,6 +1223,7 @@ enum DivInsFormats { DIV_INSFORMAT_VGI, DIV_INSFORMAT_FTI, DIV_INSFORMAT_BTI, + DIV_INSFORMAT_S3I, DIV_INSFORMAT_SBI, }; @@ -1343,6 +1344,8 @@ bool DivEngine::addInstrumentFromFile(const char* path) { format=DIV_INSFORMAT_FTI; } else if (extS==String(".bti")) { format=DIV_INSFORMAT_BTI; + } else if (extS==String(".s3i")) { + format = DIV_INSFORMAT_S3I; } else if (extS==String(".sbi")) { format = DIV_INSFORMAT_SBI; } @@ -1675,6 +1678,85 @@ bool DivEngine::addInstrumentFromFile(const char* path) { break; case DIV_INSFORMAT_BTI: break; + case DIV_INSFORMAT_S3I: + try { + reader.seek(0, SEEK_SET); + + uint8_t s3i_type = reader.readC(); + + if (s3i_type >= 2) { + ins->type = DIV_INS_OPL; + // skip internal filename - we'll use the long name description + reader.seek(12, SEEK_CUR); + + // skip reserved bytes + reader.seek(3, SEEK_CUR); + + // 12-byte opl value + uint8_t s3i_Mcharacteristics = reader.readC(); + uint8_t s3i_Ccharacteristics = reader.readC(); + uint8_t s3i_Mscaling_output = reader.readC(); + uint8_t s3i_Cscaling_output = reader.readC(); + uint8_t s3i_Meg_AD = reader.readC(); + uint8_t s3i_Ceg_AD = reader.readC(); + uint8_t s3i_Meg_SR = reader.readC(); + uint8_t s3i_Ceg_SR = reader.readC(); + uint8_t s3i_Mwave = reader.readC(); + uint8_t s3i_Cwave = reader.readC(); + uint8_t s3i_FeedConnect = reader.readC(); + + DivInstrumentFM::Operator& opM = ins->fm.op[0]; + DivInstrumentFM::Operator& opC = ins->fm.op[1]; + ins->fm.ops = 2; + opM.mult = s3i_Mcharacteristics & 0xF; + opM.ksr = ((s3i_Mcharacteristics >> 4) & 0x1); + opM.sus = ((s3i_Mcharacteristics >> 5) & 0x1); + opM.vib = ((s3i_Mcharacteristics >> 6) & 0x1); + opM.am = ((s3i_Mcharacteristics >> 7) & 0x1); + opM.tl = s3i_Mscaling_output & 0x3F; + opM.ksl = ((s3i_Mscaling_output >> 6) & 0x3); + opM.ar = ((s3i_Meg_AD >> 4) & 0xF); + opM.dr = (s3i_Meg_AD & 0xF); + opM.rr = (s3i_Meg_SR & 0xF); + opM.sl = ((s3i_Meg_SR >> 4) & 0xF); + opM.ws = s3i_Mwave; + + ins->fm.alg = (s3i_FeedConnect & 0x1); + ins->fm.fb = ((s3i_FeedConnect >> 1) & 0x7); + + opC.mult = s3i_Ccharacteristics & 0xF; + opC.ksr = ((s3i_Ccharacteristics >> 4) & 0x1); + opC.sus = ((s3i_Ccharacteristics >> 5) & 0x1); + opC.vib = ((s3i_Ccharacteristics >> 6) & 0x1); + opC.am = ((s3i_Ccharacteristics >> 7) & 0x1); + opC.tl = s3i_Cscaling_output & 0x3F; + opC.ksl = ((s3i_Cscaling_output >> 6) & 0x3); + opC.ar = ((s3i_Ceg_AD >> 4) & 0xF); + opC.dr = (s3i_Ceg_AD & 0xF); + opC.rr = (s3i_Ceg_SR & 0xF); + opC.sl = ((s3i_Ceg_SR >> 4) & 0xF); + opC.ws = s3i_Cwave; + + // Skip more stuff we don't need + reader.seek(21, SEEK_CUR); + } else { + logE("S3I PCM samples currently not supported."); + } + ins->name = reader.readString(28); + int s3i_signature = reader.readI(); + + if (s3i_signature != 0x49524353) { + logW("S3I signature invalid."); + }; + } + catch (EndOfFileException& e) { + lastError = "premature end of file"; + logE("premature end of file!\n"); + delete ins; + delete[] buf; + return false; + } + break; case DIV_INSFORMAT_SBI: try { reader.seek(0, SEEK_SET); diff --git a/src/engine/safeReader.cpp b/src/engine/safeReader.cpp index b2b955510..9b096ef79 100644 --- a/src/engine/safeReader.cpp +++ b/src/engine/safeReader.cpp @@ -30,14 +30,14 @@ bool SafeReader::seek(ssize_t where, int whence) { curSeek=where; break; case SEEK_CUR: { - ssize_t finalSeek=len+where; + ssize_t finalSeek=curSeek+where; if (finalSeek<0) return false; if (finalSeek>(ssize_t)len) return false; curSeek=finalSeek; break; } case SEEK_END: { - ssize_t finalSeek=len-where; + ssize_t finalSeek=curSeek-where; if (finalSeek<0) return false; if (finalSeek>(ssize_t)len) return false; curSeek=finalSeek; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 033ae2f03..ae176447e 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4658,9 +4658,9 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { if (!dirExists(workingDirIns)) workingDirIns=getHomeDir(); hasOpened=fileDialog->openLoad( "Load Instrument", - {"compatible files", "*.fui *.dmp *.tfi *.vgi, *.sbi", + {"compatible files", "*.fui *.dmp *.tfi *.vgi *.s3i *.sbi", "all files", ".*"}, - "compatible files{.fui,.dmp,.tfi,.vgi,.sbi},.*", + "compatible files{.fui,.dmp,.tfi,.vgi,.s3i,.sbi},.*", workingDirIns, dpiScale ); @@ -6886,6 +6886,7 @@ bool FurnaceGUI::init() { ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".tfi",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgi",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE); + ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".s3i",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".sbi",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fti",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bti",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);