home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 15
/
CD_ASCQ_15_070894.iso
/
vrac
/
mikmod43.zip
/
MODLOAD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-28
|
11KB
|
542 lines
/*
MODLOAD.C
Or how to load a module in C. Progged by MikMak :)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <alloc.h>
#include "mytypes.h"
#include "modload.h"
char protracker[]="Protracker";
char startracker[]="Startracker";
char fasttracker[]="Fasttracker";
char ins15tracker[]="15-instrument";
MODTYPE modtypes[]={
"M.K.",4,protracker, // protracker 4 channel
"M!K!",4,protracker, // protracker 4 channel
"FLT4",4,startracker, // startracker 4 channel
"FLT8",8,startracker, // startracker 8 channel
"4CHN",4,fasttracker, // fasttracker 4 channel
"6CHN",6,fasttracker, // fasttracker 6 channel
"8CHN",8,fasttracker, // fasttracker 8 channel
" ",4,ins15tracker // 15-instrument 4 channel
};
int (*SampleLoader)(FILE *fp,SAMPLEINFO *smp); // The callback sample load routine
void (*SampleUnLoader)(int handle,SAMPLEINFO *smp); // The callback sample unload routine
int ml_errno;
int ml_load15flag=0;
char *ml_errlist[]={
"No error",
"Failed allocating MODFILE structure",
"Error opening modfile",
"Error loading module header",
"Unknown type of module",
"Failed allocating pattern",
"EOF while loading pattern",
"Sample load failed"
};
enum {
ERROR_OKAY=0,
ERROR_ALLOC_STRUCT,
ERROR_OPENING_FILE,
ERROR_LOADING_HEADER,
ERROR_NOT_A_MODULE,
ERROR_ALLOC_PATTERN,
ERROR_EOF_PATTERNS,
ERROR_SAMPLE_FAILED
};
/*
Old (amiga) noteinfo:
_____byte 1_____ byte2_ _____byte 3_____ byte4_
/ \ / \ / \ / \
0000 0000-00000000 0000 0000-00000000
Upper four 12 bits for Lower four Effect command.
bits of sam- note period. bits of sam-
ple number. ple number.
Format for MIKMOD upto version 0.3:
_byte 1_ _byte 2_ __byte 3_ _byte 4_
/ \ / \ / \ / \
00000000 00000000 0000 0000 00000000
Sample note nr. zero fx fx data
Sample ranges from 0 to 31
Note number 0 means no note. ranges from 1 to 36
MIKMOD 0.4 format (same as PS16 format) :
┌─Upper two bits of instrument
│ Period
│ ││
├┐┌─┴┴─┐
00111111 period means note .. just to be clear
11111111
┌──┐┌──┐
Ins Efx
11111111
────────
Data
*/
// Periodtable for Tuning 0, Normal
UWORD pertab[60]={
1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906,
856,808,762,720,678,640,604,570,538,508,480,453,
428,404,381,360,339,320,302,285,269,254,240,226,
214,202,190,180,170,160,151,143,135,127,120,113,
107,101,95,90,85,80,75,71,67,63,60,56
};
void ConvertPattern(UBYTE *dest,UBYTE *srce,UWORD notes)
/*
Translates an amiga type pattern to a pattern with note-numbers
instead of note-periods
*/
{
UBYTE instrument,effect,effdat,note;
UWORD period;
while(notes--){
/* extract the various information from the 4 bytes that
make up a single note */
instrument=(srce[0]&0x10)|(srce[2]>>4);
period=(((UWORD)srce[0]&0xf)<<8)+srce[1];
effect=srce[2]&0xf;
effdat=srce[3];
// Convert the period to a note number
if(period!=0){
for(note=0;note<60;note++){
if(period>=pertab[note]) break;
}
if(note==60) note=0; // couldn't find period, kill note
else note++;
}
else note=0;
// And assemble the bits to the new 3-byte format
dest[0]=((instrument&0x30)<<2)|note;
dest[1]=((instrument&0xf)<<4)|effect;
dest[2]=effdat;
srce+=4;
dest+=3;
}
}
UWORD rword(UWORD p)
/*
Motorola word -> intel word
*/
{
return( ((p&0x00ff)<<8) | ((p&0xff00)>>8) );
}
void cword(UWORD *p)
{
*p=rword(*p);
}
void ConvertStr(char *d,char *s,int len)
{
strncpy(d,s,len);
d[len]='\0';
}
void Convert15To31(OLDMODULEHEADER *a,MODULEHEADER *b)
/*
Converts a 15-instrument module header into a 31 intrument header
*/
{
b->songlength=a->songlength;
b->magic1=a->magic1;
memcpy(b->positions,a->positions,128); // copy positions
memset(b->magic2,0,4); // clear magic2
memset(&b->samples[15],0,16*sizeof(MSAMPINFO)); // clear samples 15-31
}
int Check15Inst(OLDMODULEHEADER *mh)
/*
Check if it's a 15 inst. module.. you could also check if the instrument
names contain valid ascii but that still doesn't mean you can be sure
that it's a 15-instrument mod.
*/
{
int t;
for(t=0;t<15;t++){
// all finetunes should be zero
if(mh->samples[t].finetune!=0) return 0;
// all volumes should be <=64
if(mh->samples[t].volume>64) return 0;
}
if(mh->magic1>127) return 0; // and magic1 should be <128
return 1;
}
int ML_OpenModFile(MODFILE *mf,char filename[],FILE *ufp)
{
int t,modtype=0;
MODULEHEADER mh; // raw as-is module header
SAMPLEINFO *d; // new sampleinfo structure
MSAMPINFO *s; // old module sampleinfo
memset(&mh,0,sizeof(MODULEHEADER));
// Open modfile, if not already open
mf->userfp=1;
if(ufp==NULL){
ufp=fopen(filename,"rb");
mf->userfp=0;
}
mf->fp=ufp;
// Check if file was opened
if(ufp==NULL){
ml_errno=ERROR_OPENING_FILE;
return 0;
}
// try to read module header
if(!fread(&mh,sizeof(MODULEHEADER),1,ufp)){
ml_errno=ERROR_LOADING_HEADER;
return 0;
}
// find out which ID string
for(modtype=0;modtype<7;modtype++){
if(!memcmp(mh.magic2,modtypes[modtype].id,4)) break;
}
if(modtype==7){
// unknown modtype, so check if it's a 15-instrument file
if(ml_load15flag && Check15Inst((OLDMODULEHEADER *)&mh)){
Convert15To31((OLDMODULEHEADER *)&mh,&mh);
fseek(ufp,sizeof(OLDMODULEHEADER),SEEK_SET);
}
else{
ml_errno=ERROR_NOT_A_MODULE;
return 0;
}
}
// sample info to intel format
for(t=0;t<31;t++){
cword(&mh.samples[t].length);
cword(&mh.samples[t].reppos);
cword(&mh.samples[t].replen);
}
/* set module variables */
mf->numchn=modtypes[modtype].channels; // get number of channels
mf->modtype=modtypes[modtype].name; // get ascii type of mod
ConvertStr(mf->songname,mh.songname,20); // make a cstr of songname
mf->songlength=mh.songlength; // copy the songlength
memcpy(mf->positions,mh.positions,128); // copy the position array
/* Count the number of patterns */
mf->numpat=0;
for(t=0;t<128;t++){ // <-- BUGFIX... have to check ALL positions
if(mf->positions[t] > mf->numpat){
mf->numpat=mf->positions[t];
}
}
mf->numpat++;
// Finally, init the sampleinfo structures
mf->numsmp=0; // reset number of samples
s=mh.samples; // init source pointer
d=mf->samples; // init dest pointer
for(t=0;t<31;t++){
// convert the samplename
ConvertStr(d->samplename,s->samplename,22);
/* init the sampleinfo variables and
convert the size pointers to longword format */
d->finetune=s->finetune;
d->volume=s->volume;
d->reppos=s->reppos<<1;
d->replen=s->replen<<1;
d->length=s->length<<1;
/* fix replen if reppos+replen>length */
if((d->reppos+d->replen)>d->length) d->replen=d->length-d->reppos;
/* samplesize>0 ? -> increase
number of samples */
if(d->length!=0) mf->numsmp++;
s++; // point to next source sampleinfo
d++; // point to next destiny sampleinfo
}
return 1;
}
int ML_LoadPatterns(MODFILE *mf)
/*
Loads all patterns of a modfile and converts them into the
3 byte format.
*/
{
int t;
void *patbuf;
/* Allocate temporary buffer for loading
and converting the patterns */
if((patbuf=malloc(64U*4*mf->numchn))==NULL){
ml_errno=ERROR_ALLOC_PATTERN;
return 0;
}
for(t=0;t<mf->numpat;t++){
/* For each pattern, allocate a chunk
of memory */
if((mf->patterns[t]=malloc(64U*3*mf->numchn))==NULL){
ml_errno=ERROR_ALLOC_PATTERN;
break;
}
/* Load the pattern into the temp buffer
and convert it into the 3-byte format */
if(fread(patbuf,64U*4*mf->numchn,1,mf->fp)!=1){
ml_errno=ERROR_EOF_PATTERNS;
break;
}
ConvertPattern(mf->patterns[t],patbuf,64U*mf->numchn);
}
// free temp buffer
free(patbuf);
return(t==mf->numpat);
}
int ML_LoadSamples(MODFILE *mf)
{
int t,handle;
for(t=0;t<31;t++){
/* sample has to be loaded ? -> increase
number of samples and allocate memory and
load sample */
if(mf->samples[t].length!=0){
/* Call the user-supplied sample load routine.
It has to return a handle that identifies the sample */
handle=SampleLoader(mf->fp,&mf->samples[t]);
if(handle<0){ // error ?
ml_errno=ERROR_SAMPLE_FAILED;
return 0;
}
else{
mf->samples[t].handle=handle; // no error
}
}
}
if(!mf->userfp){ // if it wasn't a user supplied filehandle
fclose(mf->fp); // then close the file
mf->fp=NULL; //
}
return 1;
}
void ML_FreePatterns(MODFILE *mf)
{
int t;
for(t=0;t<128;t++){
if(mf->patterns[t]!=NULL) free(mf->patterns[t]);
}
}
void ML_FreeSamples(MODFILE *mf)
{
int t;
for(t=0;t<31;t++){
if(mf->samples[t].handle>=0) SampleUnLoader(mf->samples[t].handle,&mf->samples[t]);
}
}
void ML_FreeModFile(MODFILE *mf)
{
ML_FreeSamples(mf);
ML_FreePatterns(mf);
if(!mf->userfp && mf->fp!=NULL) fclose(mf->fp);
}
/******************************************
Next are the user-callable functions
******************************************/
void ML_Load15(int yesno)
{
ml_load15flag=yesno;
}
void ML_Free(MODFILE *mf)
{
ML_FreeModFile(mf);
free(mf);
}
int ML_Load(MODFILE *mf)
{
if(!ML_LoadPatterns(mf)) return 0;
if(!ML_LoadSamples(mf)) return 0;
return 1;
}
MODFILE *ML_Open(char filename[],FILE *fp)
{
int t;
MODFILE *mf;
ml_errno=0;
mf=malloc(sizeof(MODFILE));
if(mf==NULL){
ml_errno=ERROR_ALLOC_STRUCT;
return NULL;
}
// reset some structures
mf->fp=NULL;
for(t=0;t<128;t++) mf->patterns[t]=NULL;
for(t=0;t<31;t++) mf->samples[t].handle=-1;
if(!ML_OpenModFile(mf,filename,fp)){
ML_Free(mf);
return NULL;
}
return mf;
}
void ML_RegisterLoader(int (*Loader)(FILE *fp,SAMPLEINFO *smp))
{
SampleLoader=Loader;
}
void ML_RegisterUnLoader(void (*UnLoader)(int handle,SAMPLEINFO *smp))
{
SampleUnLoader=UnLoader;
}
const char *ML_Error(void)
{
return(ml_errlist[ml_errno]);
}