home *** CD-ROM | disk | FTP | other *** search
- /*
- 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]);
- }
-