bool CadtrackLoader::load(const std::string &filename, const CFileProvider &fp) { binistream *f = fp.open(filename); if(!f) return false; binistream *instf; char note[2]; unsigned short rwp; unsigned char chp, octave, pnote = 0; int i,j; AdTrackInst myinst; // file validation if(!fp.extension(filename, ".sng") || fp.filesize(f) != 36000) { fp.close(f); return false; } // check for instruments file std::string instfilename(filename, 0, filename.find_last_of('.')); instfilename += ".ins"; AdPlug_LogWrite("CadtrackLoader::load(,\"%s\"): Checking for \"%s\"...\n", filename.c_str(), instfilename.c_str()); instf = fp.open(instfilename); if(!instf || fp.filesize(instf) != 468) { fp.close(f); return false; } // give CmodPlayer a hint on what we're up to realloc_patterns(1,1000,9); realloc_instruments(9); realloc_order(1); init_trackord(); flags = NoKeyOn; (*order) = 0; length = 1; restartpos = 0; bpm = 120; initspeed = 3; // load instruments from instruments file for(i=0;i<9;i++) { for(j=0;j<2;j++) { myinst.op[j].appampmod = instf->readInt(2); myinst.op[j].appvib = instf->readInt(2); myinst.op[j].maintsuslvl = instf->readInt(2); myinst.op[j].keybscale = instf->readInt(2); myinst.op[j].octave = instf->readInt(2); myinst.op[j].freqrisevollvldn = instf->readInt(2); myinst.op[j].softness = instf->readInt(2); myinst.op[j].attack = instf->readInt(2); myinst.op[j].decay = instf->readInt(2); myinst.op[j].release = instf->readInt(2); myinst.op[j].sustain = instf->readInt(2); myinst.op[j].feedback = instf->readInt(2); myinst.op[j].waveform = instf->readInt(2); } convert_instrument(i, &myinst); } fp.close(instf); // load file for(rwp=0;rwp<1000;rwp++) for(chp=0;chp<9;chp++) { // read next record f->readString(note, 2); octave = f->readInt(1); f->ignore(); switch(*note) { case 'C': if(note[1] == '#') pnote = 2; else pnote = 1; break; case 'D': if(note[1] == '#') pnote = 4; else pnote = 3; break; case 'E': pnote = 5; break; case 'F': if(note[1] == '#') pnote = 7; else pnote = 6; break; case 'G': if(note[1] == '#') pnote = 9; else pnote = 8; break; case 'A': if(note[1] == '#') pnote = 11; else pnote = 10; break; case 'B': pnote = 12; break; case '\0': if(note[1] == '\0') tracks[chp][rwp].note = 127; else { fp.close(f); return false; } break; default: fp.close(f); return false; } if((*note) != '\0') { tracks[chp][rwp].note = pnote + (octave * 12); tracks[chp][rwp].inst = chp + 1; } } fp.close(f); rewind(0); return true; }
bool CmadLoader::load(const std::string &filename, const CFileProvider &fp) { binistream *f = fp.open(filename); if(!f) return false; const unsigned char conv_inst[10] = { 2,1,10,9,4,3,6,5,8,7 }; unsigned int i, j, k, t = 0; // 'MAD+' - signed ? char id[4]; f->readString(id, 4); if (strncmp(id,"MAD+",4)) { fp.close(f); return false; } // load instruments for(i = 0; i < 9; i++) { f->readString(instruments[i].name, 8); for(j = 0; j < 12; j++) instruments[i].data[j] = f->readInt(1); } f->ignore(1); // data for Protracker length = f->readInt(1); nop = f->readInt(1); timer = f->readInt(1); // init CmodPlayer realloc_instruments(9); realloc_order(length); realloc_patterns(nop,32,9); init_trackord(); // load tracks for(i = 0; i < nop; i++) for(k = 0; k < 32; k++) for(j = 0; j < 9; j++) { t = i * 9 + j; // read event unsigned char event = f->readInt(1); // convert event if (event < 0x61) tracks[t][k].note = event; if (event == 0xFF) // 0xFF: Release note tracks[t][k].command = 8; if (event == 0xFE) // 0xFE: Pattern Break tracks[t][k].command = 13; } // load order for(i = 0; i < length; i++) order[i] = f->readInt(1) - 1; fp.close(f); // convert instruments for(i = 0; i < 9; i++) for(j = 0; j < 10; j++) inst[i].data[conv_inst[j]] = instruments[i].data[j]; // data for Protracker restartpos = 0; initspeed = 1; rewind(0); return true; }
bool CcffLoader::load(const std::string &filename, const CFileProvider &fp) { binistream *f = fp.open(filename); if(!f) return false; const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 }; const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE }; int i,j,k,t=0; // '<CUD-FM-File>' - signed ? f->readString(header.id, 16); header.version = f->readInt(1); header.size = f->readInt(2); header.packed = f->readInt(1); f->readString((char *)header.reserved, 12); if (memcmp(header.id,"<CUD-FM-File>""\x1A\xDE\xE0",16)) { fp.close(f); return false; } unsigned char *module = new unsigned char [0x10000]; // packed ? if (header.packed) { cff_unpacker *unpacker = new cff_unpacker; unsigned char *packed_module = new unsigned char [header.size + 4]; memset(packed_module,0,header.size + 4); f->readString((char *)packed_module, header.size); fp.close(f); if (!unpacker->unpack(packed_module,module)) { delete unpacker; delete [] packed_module; delete [] module; return false; } delete unpacker; delete [] packed_module; if (memcmp(&module[0x5E1],"CUD-FM-File - SEND A POSTCARD -",31)) { delete [] module; return false; } } else { f->readString((char *)module, header.size); fp.close(f); } // init CmodPlayer realloc_instruments(47); realloc_order(64); realloc_patterns(36,64,9); init_notetable(conv_note); init_trackord(); // load instruments for (i=0;i<47;i++) { memcpy(&instruments[i],&module[i*32],sizeof(cff_instrument)); for (j=0;j<11;j++) inst[i].data[conv_inst[j]] = instruments[i].data[j]; instruments[i].name[20] = 0; } // number of patterns nop = module[0x5E0]; // load title & author memcpy(song_title,&module[0x614],20); memcpy(song_author,&module[0x600],20); // load order memcpy(order,&module[0x628],64); // load tracks for (i=0;i<nop;i++) { unsigned char old_event_byte2[9]; memset(old_event_byte2,0,9); for (j=0;j<9;j++) { for (k=0;k<64;k++) { cff_event *event = (cff_event *)&module[0x669 + ((i*64+k)*9+j)*3]; // convert note if (event->byte0 == 0x6D) tracks[t][k].note = 127; else if (event->byte0) tracks[t][k].note = event->byte0; if (event->byte2) old_event_byte2[j] = event->byte2; // convert effect switch (event->byte1) { case 'I': // set instrument tracks[t][k].inst = event->byte2 + 1; tracks[t][k].param1 = tracks[t][k].param2 = 0; break; case 'H': // set tempo tracks[t][k].command = 7; if (event->byte2 < 16) { tracks[t][k].param1 = 0x07; tracks[t][k].param2 = 0x0D; } break; case 'A': // set speed tracks[t][k].command = 19; tracks[t][k].param1 = event->byte2 >> 4; tracks[t][k].param2 = event->byte2 & 15; break; case 'L': // pattern break tracks[t][k].command = 13; tracks[t][k].param1 = event->byte2 >> 4; tracks[t][k].param2 = event->byte2 & 15; break; case 'K': // order jump tracks[t][k].command = 11; tracks[t][k].param1 = event->byte2 >> 4; tracks[t][k].param2 = event->byte2 & 15; break; case 'M': // set vibrato/tremolo tracks[t][k].command = 27; tracks[t][k].param1 = event->byte2 >> 4; tracks[t][k].param2 = event->byte2 & 15; break; case 'C': // set modulator volume tracks[t][k].command = 21; tracks[t][k].param1 = (0x3F - event->byte2) >> 4; tracks[t][k].param2 = (0x3F - event->byte2) & 15; break; case 'G': // set carrier volume tracks[t][k].command = 22; tracks[t][k].param1 = (0x3F - event->byte2) >> 4; tracks[t][k].param2 = (0x3F - event->byte2) & 15; break; case 'B': // set carrier waveform tracks[t][k].command = 25; tracks[t][k].param1 = event->byte2; tracks[t][k].param2 = 0x0F; break; case 'E': // fine frequency slide down tracks[t][k].command = 24; tracks[t][k].param1 = old_event_byte2[j] >> 4; tracks[t][k].param2 = old_event_byte2[j] & 15; break; case 'F': // fine frequency slide up tracks[t][k].command = 23; tracks[t][k].param1 = old_event_byte2[j] >> 4; tracks[t][k].param2 = old_event_byte2[j] & 15; break; case 'D': // fine volume slide tracks[t][k].command = 14; if (old_event_byte2[j] & 15) { // slide down tracks[t][k].param1 = 5; tracks[t][k].param2 = old_event_byte2[j] & 15; } else { // slide up tracks[t][k].param1 = 4; tracks[t][k].param2 = old_event_byte2[j] >> 4; } break; case 'J': // arpeggio tracks[t][k].param1 = old_event_byte2[j] >> 4; tracks[t][k].param2 = old_event_byte2[j] & 15; break; } } t++; } } delete [] module; // order loop restartpos = 0; // order length for (i=0;i<64;i++) { if (order[i] >= 0x80) { length = i; break; } } // default tempo bpm = 0x7D; rewind(0); return true; }
bool CffPlayer::load(const std::string& filename) { FileStream f(filename); if(!f) return false; const uint8_t conv_inst[11] = { 2, 1, 10, 9, 4, 3, 6, 5, 0, 8, 7 }; const std::array<uint16_t, 12> conv_note = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE }; // '<CUD-FM-File>' - signed ? f >> m_header; if(memcmp(m_header.id, "<CUD-FM-File>" "\x1A\xDE\xE0", 16)) { return false; } std::vector<uint8_t> module(0x10000); // packed ? if(m_header.packed) { std::unique_ptr<cff_unpacker> unpacker{ new cff_unpacker() }; std::vector<uint8_t> packedModule; packedModule.resize(m_header.size + 4, 0); f.read(packedModule.data(), m_header.size); unpacker->unpack(packedModule, module); if(module.empty()) { return false; } if(memcmp(&module[0x5E1], "CUD-FM-File - SEND A POSTCARD -", 31)) { return false; } } else { f.read(module.data(), m_header.size); } // init CmodPlayer realloc_patterns(36, 64, 9); init_notetable(conv_note); init_trackord(); // load instruments for(int i = 0; i < 47; i++) { memcpy(&m_instruments[i], &module[i * 32], sizeof(cff_instrument)); for(int j = 0; j < 11; j++) addInstrument().data[conv_inst[j]] = m_instruments[i].data[j]; m_instruments[i].name[20] = 0; } // number of patterns const auto patternCount = module[0x5E0]; // load title & author m_title = stringncpy(reinterpret_cast<const char*>(&module[0x614]), 20); m_author = stringncpy(reinterpret_cast<const char*>(&module[0x600]), 20); // load orders { static constexpr auto OrderDataOffset = 0x628; for(int i = 0; i < 64; i++) { if(module[OrderDataOffset + i] & 0x80) break; addOrder(module[OrderDataOffset + i]); } } // load tracks int t = 0; for(int i = 0; i < patternCount; i++) { uint8_t old_event_byte2[9]; memset(old_event_byte2, 0, 9); for(int channel = 0; channel < 9; channel++) { for(int row = 0; row < 64; row++) { const cff_event* event = reinterpret_cast<const cff_event *>(&module[0x669 + ((i * 64 + row) * 9 + channel) * 3]); PatternCell& cell = patternCell(t, row); // convert note if(event->byte0 == 0x6D) cell.note = 127; else if(event->byte0) cell.note = event->byte0; if(event->byte2) old_event_byte2[channel] = event->byte2; // convert effect switch(event->byte1) { case 'I': // set instrument cell.instrument = event->byte2 + 1; cell.hiNybble = cell.loNybble = 0; break; case 'H': // set tempo cell.command = Command::SetTempo; if(event->byte2 < 16) { cell.hiNybble = 0x07; cell.loNybble = 0x0D; } break; case 'A': // set speed cell.command = Command::RADSpeed; cell.hiNybble = event->byte2 >> 4; cell.loNybble = event->byte2 & 15; break; case 'L': // pattern break cell.command = Command::PatternBreak; cell.hiNybble = event->byte2 >> 4; cell.loNybble = event->byte2 & 15; break; case 'K': // order jump cell.command = Command::OrderJump; cell.hiNybble = event->byte2 >> 4; cell.loNybble = event->byte2 & 15; break; case 'M': // set vibrato/tremolo cell.command = Command::OplTremoloVibrato; cell.hiNybble = event->byte2 >> 4; cell.loNybble = event->byte2 & 15; break; case 'C': // set modulator volume cell.command = Command::ModulatorVolume; cell.hiNybble = (0x3F - event->byte2) >> 4; cell.loNybble = (0x3F - event->byte2) & 15; break; case 'G': // set carrier volume cell.command = Command::CarrierVolume; cell.hiNybble = (0x3F - event->byte2) >> 4; cell.loNybble = (0x3F - event->byte2) & 15; break; case 'B': // set carrier waveform cell.command = Command::WaveForm; cell.hiNybble = event->byte2; cell.loNybble = 0x0F; break; case 'E': // fine frequency slide down cell.command = Command::FineSlideDown; cell.hiNybble = old_event_byte2[channel] >> 4; cell.loNybble = old_event_byte2[channel] & 15; break; case 'F': // fine frequency slide up cell.command = Command::FineSlideUp; cell.hiNybble = old_event_byte2[channel] >> 4; cell.loNybble = old_event_byte2[channel] & 15; break; case 'D': // fine volume slide if(old_event_byte2[channel] & 15) { // slide down cell.command = Command::SFXFineVolumeDown; cell.loNybble = old_event_byte2[channel] & 15; } else { // slide up cell.command = Command::SFXFineVolumeUp; cell.loNybble = old_event_byte2[channel] >> 4; } break; case 'J': // arpeggio cell.hiNybble = old_event_byte2[channel] >> 4; cell.loNybble = old_event_byte2[channel] & 15; break; } } t++; } } // order loop setRestartOrder(0); // default tempo setInitialTempo(0x7D); rewind(0); return true; }