diff --git a/CMakeLists.txt b/CMakeLists.txt index 17fda0c..0f4a85d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,8 @@ set(FILEFORMATS_SOURCES "src/FileFormats/format_mucom88_dat.cpp" "src/FileFormats/format_vgi.cpp" "src/FileFormats/format_wohlstand_opn2.cpp" - "src/FileFormats/ym2612_to_wopi.cpp") + "src/FileFormats/ym2612_to_wopi.cpp" + "src/FileFormats/ym2151_to_wopi.cpp") add_library(FileFormats STATIC ${FILEFORMATS_SOURCES}) target_include_directories(FileFormats PUBLIC "src") target_link_libraries(FileFormats PUBLIC Common) diff --git a/FMBankEdit.pro b/FMBankEdit.pro index e5f05e1..18e35a9 100644 --- a/FMBankEdit.pro +++ b/FMBankEdit.pro @@ -120,6 +120,7 @@ SOURCES += \ src/FileFormats/format_vgi.cpp \ src/FileFormats/format_wohlstand_opn2.cpp \ src/FileFormats/ym2612_to_wopi.cpp \ + src/FileFormats/ym2151_to_wopi.cpp \ src/formats_sup.cpp \ src/importer.cpp \ src/latency.cpp \ @@ -157,6 +158,7 @@ HEADERS += \ src/FileFormats/format_vgi.h \ src/FileFormats/format_wohlstand_opn2.h \ src/FileFormats/ym2612_to_wopi.h \ + src/FileFormats/ym2151_to_wopi.h \ src/formats_sup.h \ src/importer.h \ src/latency.h \ diff --git a/src/FileFormats/format_vgm_import.cpp b/src/FileFormats/format_vgm_import.cpp index b3cbb3b..6474e66 100644 --- a/src/FileFormats/format_vgm_import.cpp +++ b/src/FileFormats/format_vgm_import.cpp @@ -18,6 +18,7 @@ #include "format_vgm_import.h" #include "ym2612_to_wopi.h" +#include "ym2151_to_wopi.h" #include "../common.h" #include @@ -35,7 +36,9 @@ FfmtErrCode VGM_Importer::loadFile(QString filePath, FmBank &bank) { RawYm2612ToWopi pseudoChip; RawYm2612ToWopi pseudoChip2608; + RawYm2151ToWopi pseudoChip2151; pseudoChip2608.shareInstruments(pseudoChip); + pseudoChip2151.shareInstruments(pseudoChip); char magic[4]; uint8_t numb[4]; @@ -82,6 +85,12 @@ FfmtErrCode VGM_Importer::loadFile(QString filePath, FmBank &bank) pseudoChip.passReg(1, reg, val); break; + case 0x54://Write YM2151 port + file.read(char_p(®), 1); + file.read(char_p(&val), 1); + pseudoChip2151.passReg(reg, val); + break; + case 0x56://Write YM2608 port 0 file.read(char_p(®), 1); file.read(char_p(&val), 1); @@ -116,6 +125,7 @@ FfmtErrCode VGM_Importer::loadFile(QString filePath, FmBank &bank) file.seek(file.pos() + 2); pseudoChip.doAnalyzeState(); pseudoChip2608.doAnalyzeState(); + pseudoChip2151.doAnalyzeState(); break; case 0x66://End of sound data diff --git a/src/FileFormats/ym2151_to_wopi.cpp b/src/FileFormats/ym2151_to_wopi.cpp new file mode 100644 index 0000000..6d54b72 --- /dev/null +++ b/src/FileFormats/ym2151_to_wopi.cpp @@ -0,0 +1,144 @@ +/* + * OPN2 Bank Editor by Wohlstand, a free tool for music bank editing + * Copyright (c) 2017-2019 Vitaly Novichkov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ym2151_to_wopi.h" +#include + +RawYm2151ToWopi::RawYm2151ToWopi() +{ + m_insdata.reset(new InstrumentData); + reset(); +} + +void RawYm2151ToWopi::reset() +{ + InstrumentData &insdata = *m_insdata; + insdata.cache.clear(); + insdata.caughtInstruments.clear(); + + std::memset(m_keys, 0, sizeof(m_keys)); + std::memset(m_ymram, 0, sizeof(m_ymram)); +} + +void RawYm2151ToWopi::passReg(uint8_t reg, uint8_t val) +{ + if(reg == 0x08) + m_keys[val & 3] = (val >> 3) & 15; + + m_ymram[reg] = val; +} + +void RawYm2151ToWopi::doAnalyzeState() +{ + InstrumentData &insdata = *m_insdata; + + /* Analyze dumps and take the instruments */ + for(uint8_t ch = 0; ch < 8; ch++) + { + if(m_keys[ch] == 0) + continue;//Skip if key is not pressed + + QByteArray insRaw;//Raw instrument + FmBank::Instrument ins = FmBank::emptyInst(); + for(uint8_t op = 0; op < 4; op++) + { + ins.setRegDUMUL(op, m_ymram[0x40 + (op * 8) + ch]); + ins.setRegLevel(op, m_ymram[0x60 + (op * 8) + ch]); + ins.setRegRSAt(op, m_ymram[0x80 + (op * 8) + ch]); + ins.setRegAMD1(op, m_ymram[0xa0 + (op * 8) + ch]); + ins.setRegD2(op, m_ymram[0xc0 + (op * 8) + ch]); + ins.setRegSysRel(op,m_ymram[0xe0 + (op * 8) + ch]); + insRaw.push_back((char)ins.getRegDUMUL(op)); + insRaw.push_back((char)ins.getRegLevel(op)); + insRaw.push_back((char)ins.getRegRSAt(op)); + insRaw.push_back((char)ins.getRegAMD1(op)); + insRaw.push_back((char)ins.getRegD2(op)); + insRaw.push_back((char)ins.getRegSysRel(op)); + insRaw.push_back((char)ins.getRegSsgEg(op)); + } + + ins.am = m_ymram[0x38] & 3; + ins.fm = (m_ymram[0x38] >> 4) & 7; + ins.algorithm = m_ymram[0x20] & 7; + ins.feedback = (m_ymram[0x20] >> 3) & 7; + insRaw.push_back((char)ins.getRegLfoSens()); + insRaw.push_back((char)ins.getRegFbAlg()); + + /* Maximize key volume */ + uint8_t olevels[4] = + { + ins.OP[OPERATOR1].level, + ins.OP[OPERATOR2].level, + ins.OP[OPERATOR3].level, + ins.OP[OPERATOR4].level + }; + + uint8_t dec = 0; + switch(ins.algorithm) + { + case 0:case 1: case 2: case 3: + ins.OP[OPERATOR4].level = 0; + break; + case 4: + dec = std::min({olevels[OPERATOR3], olevels[OPERATOR4]}); + ins.OP[OPERATOR3].level = olevels[OPERATOR3] - dec; + ins.OP[OPERATOR4].level = olevels[OPERATOR4] - dec; + break; + case 5: + dec = std::min({olevels[OPERATOR2], olevels[OPERATOR3], olevels[OPERATOR4]}); + ins.OP[OPERATOR2].level = olevels[OPERATOR2] - dec; + ins.OP[OPERATOR3].level = olevels[OPERATOR3] - dec; + ins.OP[OPERATOR4].level = olevels[OPERATOR4] - dec; + break; + case 6: + dec = std::min({olevels[OPERATOR2], olevels[OPERATOR3], olevels[OPERATOR4]}); + ins.OP[OPERATOR2].level = olevels[OPERATOR2] - dec; + ins.OP[OPERATOR3].level = olevels[OPERATOR3] - dec; + ins.OP[OPERATOR4].level = olevels[OPERATOR4] - dec; + break; + case 7: + dec = std::min({olevels[OPERATOR1], olevels[OPERATOR2], olevels[OPERATOR3], olevels[OPERATOR4]}); + ins.OP[OPERATOR1].level = olevels[OPERATOR1] - dec; + ins.OP[OPERATOR2].level = olevels[OPERATOR2] - dec; + ins.OP[OPERATOR3].level = olevels[OPERATOR3] - dec; + ins.OP[OPERATOR4].level = olevels[OPERATOR4] - dec; + break; + } + + //Encode volume bytes back + insRaw[1 + OPERATOR1*7] = (char)ins.getRegLevel(OPERATOR1); + insRaw[1 + OPERATOR2*7] = (char)ins.getRegLevel(OPERATOR2); + insRaw[1 + OPERATOR3*7] = (char)ins.getRegLevel(OPERATOR3); + insRaw[1 + OPERATOR4*7] = (char)ins.getRegLevel(OPERATOR4); + + if(!insdata.cache.contains(insRaw)) + { + std::snprintf(ins.name, 32, + "Ins %d, channel %d", + insdata.caughtInstruments.size(), + (int)ch); + insdata.caughtInstruments.push_back(ins); + insdata.cache.insert(insRaw); + } + } +} + +const QList &RawYm2151ToWopi::caughtInstruments() +{ + return m_insdata->caughtInstruments; +} diff --git a/src/FileFormats/ym2151_to_wopi.h b/src/FileFormats/ym2151_to_wopi.h new file mode 100644 index 0000000..ccde086 --- /dev/null +++ b/src/FileFormats/ym2151_to_wopi.h @@ -0,0 +1,46 @@ +/* + * OPN2 Bank Editor by Wohlstand, a free tool for music bank editing + * Copyright (c) 2017-2019 Vitaly Novichkov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef YM2151_TO_WOPI_H +#define YM2151_TO_WOPI_H + +#include +#include +#include +#include + +#include "../bank.h" +#include "ym2612_to_wopi.h" // instrument sharing + +class RawYm2151ToWopi +{ + typedef RawYm2612ToWopi::InstrumentData InstrumentData; + uint8_t m_keys[8]; + uint8_t m_ymram[0xFF]; + std::shared_ptr m_insdata; + +public: + RawYm2151ToWopi(); + void reset(); + template void shareInstruments(Ym &other) { m_insdata = other.m_insdata; } + void passReg(uint8_t reg, uint8_t val); + void doAnalyzeState(); + const QList &caughtInstruments(); +}; + +#endif // YM2151_TO_WOPI_H diff --git a/src/FileFormats/ym2612_to_wopi.h b/src/FileFormats/ym2612_to_wopi.h index 11c577a..b08389b 100644 --- a/src/FileFormats/ym2612_to_wopi.h +++ b/src/FileFormats/ym2612_to_wopi.h @@ -41,6 +41,8 @@ class RawYm2612ToWopi bool m_dacOn = false; std::shared_ptr m_insdata; + friend class RawYm2151ToWopi; // instrument sharing + public: RawYm2612ToWopi(); void reset();