romfile.cpp (8935B)
1 #include <fstream> 2 #include <algorithm> 3 4 #include "romfile.h" 5 #include "utils.h" 6 7 #include "unpacker.h" 8 9 #include "dsp56kEmu/dsp.h" 10 #include "dsp56kEmu/logging.h" 11 12 #include <cstring> // memcpy 13 14 #include "demoplaybackTI.h" 15 #include "dspSingle.h" 16 17 namespace virusLib 18 { 19 20 ROMFile::ROMFile(std::vector<uint8_t> _data, std::string _name, const DeviceModel _model/* = DeviceModel::ABC*/) : m_model(_model), m_romFileName(std::move(_name)), m_romFileData(std::move(_data)) 21 { 22 if(initialize()) 23 return; 24 m_romFileData.clear(); 25 m_bootRom.size = 0; 26 } 27 28 ROMFile ROMFile::invalid() 29 { 30 return ROMFile({}, {}, DeviceModel::Invalid); 31 } 32 33 bool ROMFile::initialize() 34 { 35 std::unique_ptr<std::istream> dsp(new imemstream(reinterpret_cast<std::vector<char>&>(m_romFileData))); 36 37 ROMUnpacker::Firmware fw; 38 39 // Check if we are dealing with a TI installer file, if so, unpack it first 40 if (ROMUnpacker::isValidInstaller(*dsp)) 41 { 42 fw = ROMUnpacker::getFirmware(*dsp, m_model); 43 if (!fw.isValid()) 44 { 45 LOG("Could not unpack ROM file"); 46 return false; 47 } 48 49 // Wrap into a stream so we can pass it into readChunks 50 dsp.reset(new imemstream(fw.DSP)); 51 } 52 53 const auto chunks = readChunks(*dsp); 54 55 if (chunks.empty()) 56 return false; 57 58 m_bootRom.size = chunks[0].items[0]; 59 m_bootRom.offset = chunks[0].items[1]; 60 m_bootRom.data = std::vector<uint32_t>(m_bootRom.size); 61 62 // The first chunk contains the bootrom 63 uint32_t i = 2; 64 for (; i < m_bootRom.size + 2; i++) 65 { 66 m_bootRom.data[i-2] = chunks[0].items[i]; 67 } 68 69 // The rest of the chunks is made up of the command stream 70 for (size_t j = 0; j < chunks.size(); j++) 71 { 72 for (; i < chunks[j].items.size(); i++) 73 m_commandStream.emplace_back(chunks[j].items[i]); 74 i = 0; 75 } 76 77 printf("Program BootROM size = 0x%x\n", m_bootRom.size); 78 printf("Program BootROM offset = 0x%x\n", m_bootRom.offset); 79 printf("Program CommandStream size = 0x%x\n", static_cast<uint32_t>(m_commandStream.size())); 80 81 if(isTIFamily()) 82 { 83 if (!fw.Presets.empty()) 84 { 85 for (const auto & preset : fw.Presets) 86 { 87 m_demoData.insert(m_demoData.begin(), preset.begin(), preset.end()); 88 if(DemoPlaybackTI::findDemoData(m_demoData)) 89 break; 90 91 m_demoData.clear(); 92 } 93 } 94 else 95 { 96 loadPresetFiles(); 97 } 98 99 // The Snow even has multis, but they are not sequencer compatible, drop them 100 m_multis.clear(); 101 102 if(m_multis.empty()) 103 { 104 // there is no multi in the TI presets, but there is an init multi in the F.bin 105 106 const std::string search = "Init Multi"; 107 const auto searchSize = search.size(); 108 109 for(size_t i=0; i<fw.DSP.size() && m_multis.empty(); ++i) 110 { 111 for(size_t j=0; j<searchSize && m_multis.empty(); ++j) 112 { 113 if(fw.DSP[i+j] != search[j]) 114 break; 115 116 if(j == searchSize-1) 117 { 118 TPreset preset; 119 memcpy(preset.data(), &fw.DSP[i - 4], std::size(preset)); 120 121 // validate that we found the correct data by checking part volumes. It might just be a string somewhere in the data 122 for(size_t k=0; k<16; ++k) 123 { 124 if(preset[k + 0x8b] != 0x40) 125 break; 126 127 if(k == 15) 128 { 129 for(size_t p=0; p<getPresetsPerBank(); ++p) 130 m_multis.push_back(preset); 131 } 132 } 133 } 134 } 135 } 136 } 137 138 //load presets in a fixed order, TI first, Snow last 139 auto loadFirmwarePresets = [this](const DeviceModel _model) 140 { 141 const std::unique_ptr<imemstream> file(new imemstream(reinterpret_cast<std::vector<char>&>(m_romFileData))); 142 const auto firmware = ROMUnpacker::getFirmware(*file, _model); 143 if(!firmware.Presets.empty()) 144 { 145 for (auto& presetFile: firmware.Presets) 146 { 147 imemstream stream(presetFile); 148 loadPresetFile(stream, _model); 149 } 150 } 151 }; 152 153 loadFirmwarePresets(DeviceModel::TI); 154 loadFirmwarePresets(DeviceModel::TI2); 155 loadFirmwarePresets(DeviceModel::Snow); 156 } 157 158 return true; 159 } 160 161 uint32_t ROMFile::getRomBankCount(const DeviceModel _model) 162 { 163 switch (_model) 164 { 165 case DeviceModel::TI: 166 return 26 - 7; 167 case DeviceModel::Snow: 168 return 8; 169 case DeviceModel::TI2: 170 return 26 - 5 + 4; 171 default: 172 return 8; 173 } 174 } 175 176 std::vector<ROMFile::Chunk> ROMFile::readChunks(std::istream& _file) const 177 { 178 _file.seekg(0, std::ios_base::end); 179 const auto fileSize = _file.tellg(); 180 181 uint32_t offset; 182 int lastChunkId; 183 184 if(fileSize == getRomSizeModelD()) 185 { 186 assert(isTIFamily()); 187 offset = 0x70000; 188 lastChunkId = 14; 189 } 190 else if (fileSize == getRomSizeModelABC() || fileSize == getRomSizeModelABC()/2) // the latter is a ROM without presets 191 { 192 // ABC 193 assert(isABCFamily(m_model)); 194 offset = 0x18000; 195 lastChunkId = 4; 196 } 197 else 198 { 199 LOG("Invalid ROM, unexpected filesize"); 200 return {}; 201 } 202 203 std::vector<Chunk> chunks; 204 chunks.reserve(lastChunkId + 1); 205 206 // Read all the chunks 207 for (int i = 0; i <= lastChunkId; i++) 208 { 209 _file.seekg(offset); 210 211 // Read buffer 212 Chunk chunk; 213 //file.read(reinterpret_cast<char *>(&chunk->chunk_id), 1); 214 _file.read(reinterpret_cast<char*>(&chunk.chunk_id), 1); 215 _file.read(reinterpret_cast<char*>(&chunk.size1), 1); 216 _file.read(reinterpret_cast<char*>(&chunk.size2), 1); 217 218 if(i == 0 && chunk.chunk_id == 3 && lastChunkId == 4) // Virus A and old Virus B OSs have one chunk less 219 lastChunkId = 3; 220 221 if(chunk.chunk_id != lastChunkId - i) 222 return {}; 223 224 // Format uses a special kind of size where the first byte should be decreased by 1 225 const uint16_t len = ((chunk.size1 - 1) << 8) | chunk.size2; 226 227 for (uint32_t j = 0; j < len; j++) 228 { 229 uint8_t buf[3]; 230 _file.read(reinterpret_cast<char*>(buf), 3); 231 chunk.items.emplace_back((buf[0] << 16) | (buf[1] << 8) | buf[2]); 232 } 233 234 chunks.emplace_back(chunk); 235 236 offset += 0x8000; 237 } 238 239 return chunks; 240 } 241 242 bool ROMFile::loadPresetFiles() 243 { 244 bool res = true; 245 for (auto &filename: {"S.bin", "P.bin"}) 246 { 247 std::ifstream file(filename, std::ios::binary | std::ios::ate); 248 if (!file.is_open()) 249 { 250 LOG("Failed to open preset file " << filename); 251 res = false; 252 continue; 253 } 254 res &= loadPresetFile(file, m_model); 255 file.close(); 256 } 257 return res; 258 } 259 260 bool ROMFile::loadPresetFile(std::istream& _file, DeviceModel _model) 261 { 262 _file.seekg(0, std::ios_base::end); 263 const auto fileSize = _file.tellg(); 264 265 uint32_t singleCount = 0; 266 uint32_t multiCount = 0; 267 uint32_t multiOffset = 0; 268 269 if (fileSize == 0x1b0000) // TI/TI2 270 { 271 if(_model == DeviceModel::TI2) 272 singleCount = 128 * (26 - 5); 273 else 274 singleCount = 128 * (26 - 7); 275 } 276 else if (fileSize == 0x40000) // Snow A 277 { 278 singleCount = 512; 279 } 280 else if (fileSize == 0x68000) // Snow B 281 { 282 singleCount = 512; 283 multiCount = 128; 284 multiOffset = 768; 285 } 286 else 287 { 288 LOG("Unknown file size " << fileSize << " for preset file"); 289 return false; 290 } 291 292 _file.seekg(0); 293 294 for(uint32_t i=0; i<singleCount; ++i) 295 { 296 TPreset single; 297 _file.read(reinterpret_cast<char*>(&single), sizeof(single)); 298 m_singles.emplace_back(single); 299 300 #ifdef _DEBUG 301 LOG("Loaded single " << i << ", name = " << getSingleName(single)); 302 #endif 303 } 304 305 if(multiCount) 306 { 307 const auto off = std::max(singleCount, multiOffset); 308 _file.seekg(off * 512); 309 310 for (uint32_t i = 0; i < multiCount; ++i) 311 { 312 TPreset multi; 313 _file.read(reinterpret_cast<char*>(&multi), sizeof(multi)); 314 m_multis.emplace_back(multi); 315 316 #ifdef _DEBUG 317 LOG("Loaded multi " << i << ", name = " << getMultiName(multi)); 318 #endif 319 } 320 } 321 322 return true; 323 } 324 325 std::thread ROMFile::bootDSP(DspSingle& _dsp) const 326 { 327 return _dsp.boot(m_bootRom, m_commandStream); 328 } 329 330 std::string ROMFile::getModelName() const 331 { 332 return virusLib::getModelName(getModel()); 333 } 334 335 bool ROMFile::getSingle(const int _bank, const int _presetNumber, TPreset& _out) const 336 { 337 if(isTIFamily()) 338 { 339 const auto offset = _bank * getSinglesPerBank() + _presetNumber; 340 if (offset >= m_singles.size()) 341 return false; 342 _out = m_singles[offset]; 343 return true; 344 } 345 346 const uint32_t offset = 0x50000 + (_bank * 0x8000) + (_presetNumber * getSinglePresetSize()); 347 348 return getPreset(offset, _out); 349 } 350 351 bool ROMFile::getMulti(const int _presetNumber, TPreset& _out) const 352 { 353 if(isTIFamily()) 354 { 355 if (_presetNumber >= m_multis.size()) 356 return false; 357 358 _out = m_multis[_presetNumber]; 359 return true; 360 } 361 362 return getPreset(0x48000 + (_presetNumber * getMultiPresetSize()), _out); 363 } 364 365 bool ROMFile::getPreset(const uint32_t _offset, TPreset& _out) const 366 { 367 if(_offset + getSinglePresetSize() > m_romFileData.size()) 368 return false; 369 370 memcpy(_out.data(), &m_romFileData[_offset], getSinglePresetSize()); 371 return true; 372 } 373 374 std::string ROMFile::getSingleName(const TPreset& _preset) 375 { 376 return getPresetName(_preset, 240, 249); 377 } 378 379 std::string ROMFile::getMultiName(const TPreset& _preset) 380 { 381 return getPresetName(_preset, 4, 13); 382 } 383 384 std::string ROMFile::getPresetName(const TPreset& _preset, const uint32_t _first, const uint32_t _last) 385 { 386 std::string name; 387 388 name.reserve(11); 389 390 for (uint32_t i = _first; i <= _last; i++) 391 { 392 const auto c = _preset[i]; 393 if(c < 32 || c > 127) 394 break; 395 name.push_back(static_cast<char>(c)); 396 } 397 398 return name; 399 } 400 401 }