Changes

Jump to: navigation, search

MYM

12,143 bytes added, 17 September
Created page with "MYM is a file format for ripped PSG tunes, created by Marq/Lieves!Tuore & Fit (marq@iki.fi) == Players == 2 players exist for the Amstrad CPC: one by Andy Cadley and another..."
MYM is a file format for ripped PSG tunes, created by Marq/Lieves!Tuore & Fit (marq@iki.fi)

== Players ==

2 players exist for the Amstrad CPC: one by Andy Cadley and another one by Morpheus.

They can be downloaded at http://www.kameli.net/lt/prod.htm

== File format ==

I have not been able to find a formal description of this file format.

The best we have is the source code of the original converter from YM to MYM files and vice versa.

=== ym2mym.c ===

<pre>
/*
ym2mym.c

Converts _unpacked_ YM tunes to a format better suitable for
MSX1. Supports YM2 and YM3 types well plus YM5 somehow.

30.1.2000 Marq/Lieves!Tuore & Fit (marq@iki.fi)

3.2.2000 - Added a rude YM5 loader. Skips most of the header.

Output format:

Rows in the tune, 16 bits (lobyte first)
For each register, 0 - fragment contains only unchanged data
1 - fragment contains packed data

In a packed fragment, 0 - register value is the same as before
11 - raw register data follows. Only regbits[i]
bits, not full 8
10 - offset + number of bytes from preceding
data. As many bits as are required to hold
fragment offset & counter data (OFFNUM).
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define REGS 14
#define FRAG 128 /* Nuber of rows to compress at a time */
#define OFFNUM 14 /* Bits needed to store off+num of FRAG */

void writebits(unsigned data,int bits,FILE *f);

int main(int argc,char *argv[])
{
unsigned char *data[REGS]; /* The unpacked YM data */

unsigned current[REGS];

char id[5]={0,0,0,0,0},ym_new=0,
LeOnArD[8]; /* Check string */

FILE *f;

long n,i,row,change,pack,biggest=0,hits,oldrow,remain,offi,
regbits[REGS]={8,4,8,4, 8,4,5,8, 5,5,5,8, 8,8}, /* Bits per PSG reg */
/* AND values to mask out extra bits from register data */
regand[REGS]={255,15,255,15, 255,15,31,255, 31,31,31,255, 255,255};

unsigned long length, /* Song length */
ldata; /* Needed in the loader */

if(argc!=3)
{
printf("Usage: ym2mym source.ym destination.mym\n");
printf("Raw YM files only. Uncompress with LHA.\n");
return(EXIT_FAILURE);
}

if((f=fopen(argv[1],"rb"))==NULL)
{
printf("File open error.\n");
return(EXIT_FAILURE);
}

fseek(f,0,SEEK_END);
length=ftell(f)-4;
fseek(f,0,SEEK_SET);

fread(id,1,4,f);
if(strcmp(id,"YM2!")) /* YM2 is ok */
if(strcmp(id,"YM3!")) /* YM3 is ok */
if(strcmp(id,"YM3b")) /* YM3b is ok */
{
if(!strcmp(id,"YM5!")) /* YM5 is ok but needs a */
ym_new=1; /* different loader */
else
{
printf("Unknown file format.\n");
exit(EXIT_FAILURE);
}
}
else
{
fread(id,1,4,f); /* Skip restart for YM3b */
length-=4;
}

if(ym_new) /* New YM5 format loader */
{
fread(LeOnArD,1,8,f); /* Skip checkstring */
for(n=length=0;n<4;n++) /* Number of VBL's */
{
length<<=8;
length+=fgetc(f);
}
length*=REGS;

fread(&ldata,1,3,f); /* Skip first 3 bytes of info */
if(!(fgetc(f)&1))
{
printf("Only interleaved data supported.\n");
return(EXIT_FAILURE);
}

if(fgetc(f) || fgetc(f)) /* Number of digidrums */
{
printf("Digidrums not supported.\n");
return(EXIT_FAILURE);
}

fread(&ldata,1,4,f); /* Skip external freq */
fread(&ldata,1,2,f); /* Skip VBL freq */
fread(&ldata,1,4,f); /* Skip loop position */
fread(&ldata,1,2,f); /* Skip additional data */

while(fgetc(f)) /* Skip song name */
;
while(fgetc(f)) /* Skip author name */
;
while(fgetc(f)) /* Skip comments */
;
}

/* Old YM2/YM3 format loader */
for(n=0;n<REGS;n++) /* Allocate memory & read data */
{
/* Allocate extra fragment to make packing easier */
if((data[n]=malloc(length/REGS+FRAG))==NULL)
{
printf("Out of memory.\n");
return(EXIT_FAILURE);
}
memset(data[n],0,length/REGS+FRAG);
fread(data[n],1,length/REGS,f);
}

if(ym_new) /* Let's mask the extra YM5 data out */
{
for(n=0;n<REGS;n++)
for(row=0;row<length/REGS;row++)
data[n][row]&=regand[n];
}

fclose(f);

if((f=fopen(argv[2],"wb"))==NULL)
{
printf("Cannot open destination file.\n");
return(EXIT_FAILURE);
}

for(n=0;n<REGS;n++) /* Set current values to impossible */
current[n]=0xffff;

fputc(length/REGS&0xff,f); /* Write tune length */
fputc(length/REGS>>8,f);

for(n=0;n<length/REGS;n+=FRAG) /* Go through fragments... */
{
for(i=0;i<REGS;i++) /* ... for each register */
{
for(row=change=0;row<FRAG;row++)
if(data[i][n+row]!=current[i])
change=1;

if(!change) /* No changes in the whole fragment */
{
writebits(0,1,f);
continue; /* Skip the next pass */
}
else
writebits(1,1,f);

for(row=0;row<FRAG;row++)
{
if(data[i][n+row]!=current[i])
{
change=1;
current[i]=data[i][n+row];

biggest=0;
if(n) /* Skip first fragment */
{
offi=0;
remain=FRAG-row;

/* Go through the preceding data and try to find
similar data */
for(oldrow=0;oldrow<FRAG;oldrow++)
{
hits=0;
for(pack=0;pack<remain;pack++)
{
if(data[i][n+row+pack]==data[i][n-FRAG+row+oldrow+pack]
&& oldrow+pack<FRAG)
hits++;
else
break;
}
if(hits>biggest) /* Bigger sequence found */
{
biggest=hits;
offi=oldrow;
}
}
}

if(biggest>1) /* Could we pack data? */
{
row+=biggest-1;
current[i]=data[i][n+row];
writebits(2,2,f);
writebits((offi<<OFFNUM/2)+(biggest-1),OFFNUM,f);
}
else /* Nope, write raw bits */
{
writebits(3,2,f);
writebits(data[i][n+row],regbits[i],f);
}
}
else /* Same as former value, write 0 */
writebits(0,1,f);
}
}
}

writebits(0,0,f); /* Pad to byte size */
fclose(f);
return(EXIT_SUCCESS);
}

/* Writes bits to a file. If bits is 0, pads to byte size. */
void writebits(unsigned data,int bits,FILE *f)
{
static unsigned char byte=0;

static int off=0;

int n;

if(!bits && off)
{
off=byte=0;
fputc(byte,f);
return;
}

/* Go through the bits and write a whole byte if needed */
for(n=0;n<bits;n++)
{
if(data&(1<<bits-1-n))
byte|=0x80>>off;

if(++off==8)
{
fputc(byte,f);
off=byte=0;
}
}
}

/* EOS */
</pre>

<br>

=== mym2ym.c ===

<pre>
/*
mym2ym.c

Converts MYM files back to upacked YM3.

31.1.2000 Marq/Lieves!Tuore & Fit (marq@iki.fi)
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define REGS 14
#define FRAG 128 /* Nuber of rows to compress at a time */
#define OFFNUM 14 /* Bits needed to store off+num of FRAG */

unsigned readbits(int bits,FILE *f);

int main(int argc,char *argv[])
{
unsigned char *data[REGS], /* The unpacked YM data */
c;

unsigned current[REGS];

FILE *f;

long n,i,row,index,compoff,compnum,
bytes=0,
regbits[REGS]={8,4,8,4, 8,4,5,8, 5,5,5,8, 8,8}; /* Bits per PSG reg */

unsigned long rows;

if(argc!=3)
{
printf("Usage: mym2ym source.mym destination.ym\n");
printf("Raw YM files only. Compress with LHA.\n");
return(EXIT_FAILURE);
}

if((f=fopen(argv[1],"rb"))==NULL)
{
printf("File open error.\n");
return(EXIT_FAILURE);
}

rows=fgetc(f); /* Read the number of rows */
rows+=fgetc(f)<<8u;

for(n=0;n<REGS;n++) /* Allocate memory for rows */
{
if((data[n]=malloc(rows+FRAG))==NULL)
{
printf("Out of memory.\n");
exit(EXIT_FAILURE);
}
}

for(n=0;n<rows;n+=FRAG) /* Go through rows... */
{
for(i=0;i<REGS;i++) /* ... and registers */
{
index=0;
if(!readbits(1,f)) /* Totally unchanged fragment */
{
for(row=0;row<FRAG;row++)
data[i][n+row]=current[i];
continue;
}

while(index<FRAG) /* Packed fragment */
{
if(!readbits(1,f)) /* Unchanged register */
{

data[i][n+index]=current[i];
index++;
}
else
{
if(readbits(1,f)) /* Raw data */
{
c=readbits(regbits[i],f);
current[i]=data[i][n+index]=c;
index++;
}
else /* Reference to previous data */
{
compoff=readbits(OFFNUM/2,f)+index;
compnum=readbits(OFFNUM/2,f)+1;

for(row=0;row<compnum;row++)
{
c=data[i][n-FRAG+compoff+row];
data[i][n+index]=current[i]=c;
index++;
}
}
}
}
}
}

fclose(f);

if((f=fopen(argv[2],"wb"))==NULL)
{
printf("Cannot open destination file.\n");
return(EXIT_FAILURE);
}

/* Write uncompressed data to YM3 format */
fwrite("YM2!",1,4,f);
for(n=0;n<REGS;n++)
fwrite(data[n],1,rows,f);
fclose(f);

return(EXIT_SUCCESS);
}

/* Reads bits from a while */
unsigned readbits(int bits,FILE *f)
{
static unsigned char byte;

static int off=7;

unsigned n,data=0;

/* Go through the bits and read a whole byte if needed */
for(n=0;n<bits;n++)
{
data<<=1;
if(++off==8)
{
byte=fgetc(f);
off=0;
}

if(byte&(0x80>>off))
data++;
}
return(data);
}

/* EOS */
</pre>
8,990
edits