So I've written a tracker, and I'd like to support s3m files so I can be played in other trackers.
Problem is modplug tracker isn't accepting the file I'm writing.
Its a single function, Its got extra stuff in for converting the data across from my system, so it obfuscates the code a bit unfortunately.
The code is a bit messy and has some spare variables, I'm actually rendering the samples with a synthesizer, just to be clear.
Im setting up instruments, rendering the samples, and setting the offsets at the top, and all the disk writing is at the bottom.
I made it from an s3m loader on a bisquit youtube video, and it has some wierd parts to it I dont really like the look of.
If only I could get an actual s3m file writer! that would help me heaps.
Adding my music information to the s3m made the file alot bigger, all the writes are at the bottom where the fopen is.
So here is the function in entirety:
[code = “c++”]
#define MAX_PATLENGTH 10000
#define MAX_SAMPLELENGTH 1000000
char* data_patterns = new char[128 * MAX_PATLENGTH]; //the pattern information is in bytes
char* data_samples = new char[128 * MAX_SAMPLELENGTH]; //the sample information in bytes.
struct s3mheader
{
char name[28]; // song name
unsigned char eofchar, typ, dummy[2];
unsigned short ordnum, insnum, patnum, flags, cwtv, ffi;
char scrm[4];
unsigned char Vxx, Axx, Txx, mastervolume, uc, dp, dummy2[8];
unsigned short special;
unsigned char channelsettings[32];
// The rest of this struct is filled on demand
unsigned char orders[256], * patdata[100], * patend[100];
};
struct s3minst
{
unsigned char type;
char filename[12];
unsigned char filepos[3];
long length, loopbegin, loopend;
unsigned char volume, dummy, packflag, flags;
unsigned long c4spd;
unsigned char* sampledata; // internal, used in runtime
double c4spd_factor; // internal, used in runtime
unsigned char name[28], scri[4];
};
void save_s3m2(const char* filename, int voices)
{
s3m_header s3h;
s3mheader name;
s3minst ins[100];
unsigned short inspointers[99];
unsigned short patpointers[100];
unsigned long samplepointers[100];
uint i;
uint j, k;
uint length1[101];
//setup instruments.
for (i = 0; i < voices; i++)
{
memset(&ins[i], 0, sizeof(s3minst));
//render the wave file here
tvoice[0] = cur_voice;
tnote[0] = DN1;
tstop[0] = false;
tstop2[0] = false;
uint j;
for (j = 0; j < mod1[0].voice[i].end - mod1[0].voice[i].start; j++)
{
data_samples[i * MAX_SAMPLELENGTH + j] = render_synth(0, 1, j, false);
}
strcpy_m(ins[i].filename, mod1[0].voice[i].name, strlen(mod1[0].voice[i].name));
ins[i].type = 0;
ins[i].scri[0] = 'S';
ins[i].scri[1] = 'C';
ins[i].scri[2] = 'R';
ins[i].scri[3] = 'S';
ins[i].length = mod1[0].voice[i].end - mod1[0].voice[i].start; //the wave file size
ins[i].flags = 1 << 6;
ins[i].name[0] = 0;
ins[i].loopbegin = 0;
ins[i].loopend = ins[i].length;
ins[i].volume = 0xFF;
ins[i].c4spd = 168;
ins[i].c4spd_factor = 229079296.0 / ins[i].c4spd;
}
int off, offd16, offm16;
//set offsets.
for (i = 0; i < voices; i++)
{
if (i == 0)
{
off = 0x60 + mod1[0].patts + voices * 2 + mod1[0].patts * 2;
offd16 = off / 16;
offm16 = off % 16;
if (offm16 > 0) offd16++;
inspointers[i] = offd16;
}
else
{
off = inspointers[i-1]+sizeof(s3minst);
offd16 = off / 16;
offm16 = off % 16;
if (offm16 > 0) offd16++;
inspointers[i] = offd16;
}
}
//pattern offsets
for (i = 0; i < mod1[0].patts; i++)
{
//set pattern data
memset(&data_patterns[i * MAX_PATLENGTH], 0, MAX_PATLENGTH);
length1[i] = 0;
for (k = 0; k < mod1[0].patt[i].ticks; k++)
{
for (j = 0; j < TRACKS; j++)
{
if (mod1[0].patt[i].track[j].note[k] != NON)
{
unsigned char byte = j;
byte += 1 << 5;
byte += 1 << 6;
data_patterns[i * MAX_PATLENGTH + length1[i]] = byte;
length1[i]++;
data_patterns[i * MAX_PATLENGTH + length1[i]] = mod1[0].patt[i].track[j].note[k];
length1[i]++;
data_patterns[i * MAX_PATLENGTH + length1[i]] = mod1[0].patt[i].track[j].voice[k];
length1[i]++;
data_patterns[i * MAX_PATLENGTH + length1[i]] = mod1[0].patt[i].track[j].amp[k]*64/255;
length1[i]++;
}
else
if (mod1[0].patt[i].track[j].amp[k]>0)
{
unsigned char byte = j;
byte += 1 << 6;
data_patterns[i * MAX_PATLENGTH + length1[i]] = byte;
length1[i]++;
data_patterns[i * MAX_PATLENGTH + length1[i]] = mod1[0].patt[i].track[j].amp[k]*64/255;
length1[i]++;
}
}
data_patterns[i * MAX_PATLENGTH + length1[i]] = 0;
length1[i]++;
}
if (i == 0)
{
off = inspointers[voices - 1] * 16 + sizeof(s3minst);
offd16 = off / 16;
offm16 = off % 16;
if (offm16 > 0) offd16++;
patpointers[i] = offd16;
}
else
{
off = patpointers[i - 1] * 16 + length1[i - 1];
offd16 = off / 16;
offm16 = off % 16;
if (offm16 > 0) offd16++;
patpointers[i] = offd16;
}
}
//setup sample offsets
for (i = 0; i < voices; i++)
{
if (i == 0)
{
off = patpointers[mod1[0].patts - 1] * 16 + length1[mod1[0].patts - 1];
samplepointers[i] = off;
unsigned long sp = samplepointers[i];
unsigned long big = sp / 0x100000UL/2;
ins[i].filepos[0] = big;
sp -= big *0x100000UL * 2;
int medium = sp / 0x1000UL;
ins[i].filepos[2] = medium;
sp -= medium;
int sps = sp % 0x10UL;
sp /= 0x10UL;
if (sps > 1)
{
sp++;
}
ins[i].filepos[1] = sp;
}
else
{
off = samplepointers[i - 1] + ins[i - 1].length;
samplepointers[i] = off;
unsigned long sp = samplepointers[i];
unsigned long big = sp / 0x100000UL / 2;
ins[i].filepos[0] = big;
sp -= big * 0x100000UL * 2;
int medium = sp / 0x1000UL;
ins[i].filepos[2] = medium;
sp -= medium;
int sps = sp % 0x10UL;
sp /= 0x10UL;
if (sps > 1)
{
sp++;
}
ins[i].filepos[1] = sp;
}
}
strcpy_m(name.name, "Scream", strlen("Scream"));
char orders[256];
for (i = 0; i < mod1[0].patts; i++) { orders[i] = i; }
memset(&name, 0, sizeof(s3mheader));
name.ordnum = mod1[0].patts; //<256
name.insnum = voices; //<=99
name.patnum = mod1[0].patts; //<= 100
name.eofchar = 0x1A;
name.typ = 0x10;
name.scrm[0] = 'S';
name.scrm[1] = 'C';
name.scrm[2] = 'R';
name.scrm[3] = 'M';
FILE* fp;
fopen_s(&fp, filename, "wb+");
fwrite(&name, 1, 0x60, fp);
fwrite(&orders, 1, mod1[0].patts, fp);
fwrite(&inspointers, 2, voices, fp);
fwrite(&patpointers, 2, mod1[0].patts, fp);
for (i = 0; i < voices; ++i)
{
fseek(fp, inspointers[i] * 16UL, SEEK_SET);
fwrite(&ins[i], 1, 0x50, fp);
unsigned long smppos = ins[i].filepos[1] * 0x10UL
+ ins[i].filepos[2] * 0x1000UL
+ ins[i].filepos[0] * 0x100000UL + ins[i].filepos[0] * 0x100000UL;
fseek(fp, smppos, SEEK_SET);
fwrite(&data_samples[i*MAX_SAMPLELENGTH], 1, ins[i].length, fp);
}
for (unsigned p = 0; p < mod1[0].patts; ++p)
{
unsigned short length = 2;
fseek(fp, patpointers[p] * 16UL, SEEK_SET);
fwrite(&length1[p], 1, 2, fp);
fwrite(&data_patterns[p*MAX_PATLENGTH], 1, length - 2, fp);
}
fclose(fp);
}
[/code]
I've got no idea what I have got wrong, So apart from looking at my function, which might be a bit bothersome I don't have an idea of what I can do in the future, I'm pretty much stuck.
All I have is access to loaders, not savers, so I might be missing something in the save, that the load hasnt got in it.
Can someone help?