#include /* S3M handling interface * Copyright (C) 1992,2003 Bisqwit (http://iki.fi/bisqwit/) */ #include "s3m.hh" using std::fopen; using std::fclose; using std::fread; using std::fgetc; using std::fwrite; using std::fputc; using std::printf; using std::memset; using std::isprint; static unsigned readword(FILE* fp) { int c = fgetc(fp); return (fgetc(fp)<<8) | c; } static void writeword(FILE* fp, unsigned w) { fputc(w&255, fp); fputc(w>>8, fp); } static void newpara(FILE* fp) { long pos = ftell(fp); unsigned liika = pos & 15; if(!liika)return; static const char tmp[16] = {0}; fwrite(tmp, 1, 16-liika, fp); } S3M::S3M(FILE* fp) : name("?"), flags(0), version(0x1320), ffi(2), globalvolume(64), cmdA(6), cmdT(125), mastervolume(48), stereo(false), ultraclick(10), panflags(0xFC), ok(true) { memset(pansets, 0, sizeof pansets); memset(chansets, 255, sizeof chansets); if(fp) { ok = Load(fp); } } void S3M::instrument::Clear() { type=0; filename = ""; memset(data, 0, sizeof data); name = ""; oldparaptr=0; audio.clear(); } void S3M::instrument::MakeSMP() { // data bytes format: // 0..3: Length // 4..7: Loop begin // 8..11: Loop end // 12: Volume // 14: 0 (unpacked) // 15: 0=no loop, 1=loop // 16..19: C2Spd type = 1; data[0] = data[1] = data[2] = data[3] = 0; data[4] = data[5] = data[6] = data[7] = 0; data[8] = data[9] = data[10] = data[11] = 0; data[12] = 64; data[14] = 0; data[15] = 1; data[16] = 8363 & 255; data[17] = 8363 / 256; data[18] = data[19] = 0; } void S3M::instrument::MakeAME() { type = 2; data[12] = 64; data[14] = 0; data[15] = 1; data[16] = 8363 & 255; data[17] = 8363 / 256; } void S3M::instrument::SetLoop(unsigned begin, unsigned end) { data[4] = begin & 255; data[5] = begin / 256; data[8] = end & 255; data[9] = end / 256; data[15] = begin != end; } void S3M::instrument::SetC4SPD(unsigned c4spd) { data[16] = c4spd & 255; data[17] = (c4spd >> 8) & 255; data[18] = (c4spd >> 16) & 255; data[19] = (c4spd >> 24) & 255; } void S3M::instrument::SetVolume(unsigned char vol) { data[12] = vol; } void S3M::event::Clear() { note=vol=255; ins=cmd=info=0; } bool S3M::Load(FILE* fp) { ok = false; char Buf[32]; fread(Buf, 1, 32, fp); if(Buf[0x1D] != 16) { /* invalid format */ return false; } Buf[0x1C] = 0; name = Buf; patterns.clear(); unsigned ordnum = readword(fp); unsigned insnum = readword(fp); unsigned patnum = readword(fp); flags = readword(fp); version = readword(fp); ffi = readword(fp); if(fgetc(fp)!='S' || fgetc(fp)!='C' || fgetc(fp)!='R' || fgetc(fp)!='M') { /* invalid format */ return false; } instrus.resize(insnum); patterns.resize(patnum); globalvolume = fgetc(fp); cmdA = fgetc(fp); cmdT = fgetc(fp); mastervolume = fgetc(fp); stereo = mastervolume&128; mastervolume &= 127; ultraclick = fgetc(fp); panflags = fgetc(fp); fread(Buf, 1, 10, fp); fread(chansets, 1, 32, fp); orders.resize(ordnum); fread(&orders[0], 1, ordnum, fp); vector insptr(insnum); vector patptr(patnum); for(unsigned a=0; a insptr(insnum); long instabptr = ftell(fp); for(unsigned a=0; a patptr(patnum); long pattabptr = ftell(fp); for(unsigned a=0; a> 4; instrument& tmp = instrus[a]; fputc(tmp.type, fp); strncpy(Buf, tmp.filename.c_str(), 12); fwrite(Buf, 1, 12, fp); Buf[0] = Buf[1] = Buf[2] = 0; fwrite(Buf, 1, 3, fp); // memseg fwrite(tmp.data, 1, 32, fp); strncpy(Buf, tmp.name.c_str(), 28); fwrite(Buf, 1, 28, fp); fwrite("SCRS", 1, 4, fp); } for(unsigned a=0; a> 4; writeword(fp, patterns[a].size()+2); fwrite(&patterns[a][0], 1, patterns[a].size(), fp); } for(unsigned a=0; a> 4; fwrite(&instrus[a].audio[0], 1, audiolen, fp); } long p = ftell(fp); fseek(fp, insptr[a] * 16 + 13, SEEK_SET); Buf[0] = memseg >> 16; Buf[1] = (memseg ) & 255; Buf[2] = (memseg >> 8) & 255; fwrite(Buf, 1, 3, fp); // memseg if(audiolen) { Buf[0] = audiolen & 255; Buf[1] = (audiolen >> 8) & 255; fwrite(Buf, 1, 2, fp); } fseek(fp, p, SEEK_SET); } fseek(fp, instabptr, SEEK_SET); for(unsigned a=0; a= 32)return; chansets[chan] = type; pansets[chan] = pan; } void S3M::setorder(unsigned ordernum, unsigned char value) { if(ordernum > 255)ordernum = 255; if(orders.size() <= ordernum) orders.resize(ordernum+1); orders[ordernum] = value; } S3M::instrument& S3M::getinstrument(unsigned instrunum) { if(instrunum >= 70)instrunum = 70; if(instrus.size() <= instrunum) instrus.resize(instrunum+1); return instrus[instrunum]; } S3M::pattern& S3M::getpattern(unsigned patnum) { if(patnum >= 99)patnum = 99; if(patterns.size() <= patnum) patterns.resize(patnum+1); return patterns[patnum]; } void S3M::eventtable::setgeometry(unsigned rows, unsigned chans) { rowcount = rows; channelcount = chans; events.resize(rows*chans); } void S3M::eventtable::loadchannel(unsigned chan, const vector& channel) { if(rowcount < channel.size()) { rowcount = channel.size(); events.resize(rowcount * channelcount); } for(unsigned a=0; a