/*************************************************************************** **************************************************************************** **************************************************************************** * * FunktrackerGOLD - By Jason Nunn * Copyright (C) 1996,1998 Jason Nunn * * FunktrackerGOLD now comes under the GNU General Public License. Please * read the COPYING notice in this distribution. * * ================================================================ * **************************************************************************** **************************************************************************** ***************************************************************************/ #include #include #include #include #include "funktracker_defs.h" #include "dsp_mixxer.h" #include "funktracker.h" #include "funkload.h" /*************************************************************************** * ***************************************************************************/ #define SO_TT_SIZE 2 void get_environment(void) { funk_info.funk_cpu_type = FKCPU_FREEBSD; } /*************************************************************************** * * 'info' code (diagram much for readable than in Funklite.asm ;): * * 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 * \--BPM rate-/ | \-CPU-/ \-card/ \----year---/ \-month-/ \--day--/ * | | * / \ * 16 bit = 1 year + 1980 * ***************************************************************************/ void chg_funk_funktype(void) { char tmp[3]; strncpy(funk_hr_ptr->funk_type,"F200",4); sprintf(tmp,"%d",funk_info.no_active_channels); if(funk_info.no_active_channels < 10) { funk_hr_ptr->funk_type[2] = 0x30; funk_hr_ptr->funk_type[3] = tmp[0]; } else { funk_hr_ptr->funk_type[2] = tmp[0]; funk_hr_ptr->funk_type[3] = tmp[1]; } } void new_funk_module(void) { time_t timer = time(NULL); struct tm *tblock = localtime(&timer); register int x; ferr_val = FERR_OK; funk_info.bpm_rate = 125; dealloc_funk_mem(); /*CREATE & CLEAR HEADER*/ ferr_val = alloc_funk_hr(); if(ferr_val == FERR_OK) { strncpy(funk_hr_ptr->sig,"Funk",4); chg_funk_funktype(); x = tblock->tm_mon + 1; funk_hr_ptr->info[0] = tblock->tm_mday & 0x1f; funk_hr_ptr->info[0] |= (x & 0x7) << 5; funk_hr_ptr->info[1] = (x & 0xf) >> 3; x = tblock->tm_year - 80; if(x < 0) x = 80; funk_hr_ptr->info[1] |= (x & 0x7f) << 1; funk_hr_ptr->info[2] = (funk_info.funk_cpu_type << 4) | (funk_info.funk_card_type & 0xf); funk_hr_ptr->info[3] = 0; if(funk_info.sample_precision == 16) funk_hr_ptr->info[3] |= 1; set_BPM(); funk_hr_ptr->loop_order = 0xff; for(x = 0;x < 256;x++) funk_hr_ptr->order_list[x] = 0xff; for(x = 0;x < 128;x++) funk_hr_ptr->break_list[x] = 0x3f; for(x = 0;x < 64;x++) clear_sam_entry(&funk_hr_ptr->funk_sb[x]); /*CREATE & CLEAR PATTERNS*/ ferr_val = alloc_pat_blk(); varedit_init(); } } /*************************************************************************** * S A V E S O N G ***************************************************************************/ int dsp_save_sample(FILE *fp,int sample_no) { register unsigned long samsize = funk_hr_ptr->funk_sb[sample_no].length * (funk_info.sample_precision >> 3); if(fwrite(funk_sam_ptrs[sample_no],1,samsize,fp) != samsize) { ferr_val = FERR_FWRITE; return 0; } return 1; } void save_funk_module(char *filename) { FILE *funk_fp; register int x,a = 0; long pattern_block_size; void save(void) { register int x; if(fwrite(funk_hr_ptr,sizeof(tfunk_hr),1,funk_fp) != 1) { ferr_val = FERR_FWRITE; return; } if(fwrite(funk_pat_ptr,sizeof(tslot), pattern_block_size,funk_fp) != pattern_block_size) { ferr_val = FERR_FWRITE; return; } for(x = 0;x < 64;x++) if(funk_hr_ptr->funk_sb[x].length) if(!dsp_save_sample(funk_fp,x)) return; } ferr_val = FERR_OK; find_pats_seqs(); for(x = 0;x < 256;x++) if(funk_hr_ptr->order_list[x] != 0xFF) { a = 1; break; } if(!a) { ferr_val = FERR_ESEQTABLE; return; } else { set_BPM(); pattern_block_size = funk_info.no_of_patterns * 64 * funk_info.no_active_channels; funk_hr_ptr->LZH_check_size = sizeof(tfunk_hr) + (pattern_block_size * sizeof(tslot)); for(x = 0;x < 64;x++) funk_hr_ptr->LZH_check_size += funk_hr_ptr->funk_sb[x].length * ((funk_hr_ptr->info[3] & 0x1) + 1); if((funk_fp = fopen(filename,"wb")) != NULL) { save(); fclose(funk_fp); } else ferr_val = FERR_FCREATE; } } /*************************************************************************** * * read sample data * ***************************************************************************/ /*************************************** * ***************************************/ FILE *tmp_f; #define FNBUF_SIZE 4096 #pragma pack(1) void *sam_load_tb; void *sam_load_tb2; #pragma pack() void write_bloc_sambloc(unsigned int *samoutpos,int prec) { if(*samoutpos > 0) { if(fwrite(sam_load_tb2,prec,*samoutpos,tmp_f) != *samoutpos) { ferr_val = FERR_FWRITE; return; } *samoutpos = 0; } } void *load_samblock( FILE *samfile, int sam_no, unsigned long read_length, double saminfreqinc, int prec) { unsigned long rs; void *sam_alloc = NULL; double saminpos; unsigned int samoutpos = 0; do { if(read_length > FNBUF_SIZE) rs = FNBUF_SIZE; else rs = read_length; if(fread(sam_load_tb,prec,rs,samfile) != rs) { ferr_val = FERR_FREAD; return NULL; } read_length -= rs; if(rs > 0) { saminpos = 0; do { if(samoutpos == FNBUF_SIZE) write_bloc_sambloc(&samoutpos,prec); if(ferr_val != FERR_OK) return NULL; if((unsigned int)saminpos < rs) { #pragma pack(1) if(prec == 1) *(uDB *)((uDB *)sam_load_tb2 + samoutpos++) = *(uDB *)((uDB *)sam_load_tb + (unsigned int)saminpos); else *(uDW *)((uDW *)sam_load_tb2 + samoutpos++) = *(uDW *)((uDW *)sam_load_tb + (unsigned int)saminpos); #pragma pack() saminpos += saminfreqinc; } } while((unsigned int)saminpos < rs); } } while(rs); write_bloc_sambloc(&samoutpos,prec); if(ferr_val != FERR_OK) return NULL; fseek(tmp_f,0,SEEK_END); funk_hr_ptr->funk_sb[sam_no].length = ftell(tmp_f); fseek(tmp_f,0,SEEK_SET); if((sam_alloc = malloc(funk_hr_ptr->funk_sb[sam_no].length)) == NULL) { ferr_val = FERR_MALLOC; return NULL; } if(prec == 2) funk_hr_ptr->funk_sb[sam_no].length >>= 1; if(fread(sam_alloc,prec,funk_hr_ptr->funk_sb[sam_no].length,tmp_f) != funk_hr_ptr->funk_sb[sam_no].length) { ferr_val = FERR_FREAD; free(sam_alloc); return NULL; } return sam_alloc; } void *load_samdata( FILE *samfile, int sam_no, unsigned long read_length, double saminfreqinc, int prec) { void *sam_alloc = NULL; int alloc_size = FNBUF_SIZE * prec; if((sam_load_tb = malloc(alloc_size)) != NULL) { if((sam_load_tb2 = malloc(alloc_size)) != NULL) { if((tmp_f = tmpfile()) != NULL) { sam_alloc = load_samblock(samfile,sam_no,read_length,saminfreqinc,prec); fclose(tmp_f); } else ferr_val = FERR_FOPEN; } else ferr_val = FERR_MALLOC; free(sam_load_tb); } else ferr_val = FERR_MALLOC; return sam_alloc; } /*************************************************************************** * ***************************************************************************/ void set_sample_name(int sam_no,char *filename) { register int x; register int b = strlen(filename); for(x = 0;x < 19;x++) { if(x < b) { unsigned char a = filename[x]; if((a >= 32) && (a <= 127)) funk_hr_ptr->funk_sb[sam_no].sname[x] = filename[x]; else funk_hr_ptr->funk_sb[sam_no].sname[x] = ' '; } else funk_hr_ptr->funk_sb[sam_no].sname[x] = ' '; } } void unsign_8bit_data(void *sam_ptr,unsigned long num2read) { register unsigned long a; if(funk_info.sample_precision == 8) for(a = 0;a < num2read;a++) *(unsigned char *)(sam_ptr + a) ^= 0x80; } /*************************************************************************** * * load 8 bit unsigned file (.SND, .RAW) * ***************************************************************************/ void snd_load_sample(int sam_no,char *filename,double resamf) { FILE *fp; register unsigned long file_size; ferr_val = FERR_OK; if((fp = fopen(filename,"rb")) == NULL) { ferr_val = FERR_FOPEN; return; } file_size = find_file_size(fp); if(funk_info.sample_precision == 16) file_size >>= 1; funk_sam_ptrs[sam_no] = load_samdata(fp,sam_no,file_size,resamf, funk_info.sample_precision >> 3); fclose(fp); if(funk_sam_ptrs[sam_no] != NULL) { unsign_8bit_data(funk_sam_ptrs[sam_no],funk_hr_ptr->funk_sb[sam_no].length); set_sample_name(sam_no,filename); } } /*************************************************************************** * * Load MessyWindows WAVE file * ***************************************************************************/ typedef struct { sDB rID[4]; uDD rLen; sDB wID[4]; sDB fId[4]; uDD fLen; uDW wFormatTag; uDW nChannels; uDW nSamplesPerSec; uDW nAvgBytesPerSec; uDW nBlockAlign; uDW FormatSpecific; uDD blank; sDB dId[4]; uDD dLen; } twav_hr; void wav_load_sample(int sam_no,char *filename,double resamf) { FILE *fp; twav_hr wav_hr; void wav_load_sample_data(void) { if(fread(&wav_hr,1,sizeof(twav_hr),fp) != sizeof(twav_hr)) { ferr_val = FERR_FREAD; return; } if((strncmp(wav_hr.rID,"RIFF",4) != 0) && (strncmp(wav_hr.wID,"WAVE",4) != 0) && (strncmp(wav_hr.fId,"fmt ",4) != 0) && (strncmp(wav_hr.dId,"data",4) != 0)) { ferr_val = FERR_SAMUNKNOWN; return; } if(funk_info.sample_precision == 16) wav_hr.dLen >>= 1; funk_sam_ptrs[sam_no] = load_samdata(fp,sam_no,wav_hr.dLen,resamf, funk_info.sample_precision >> 3); if(funk_sam_ptrs[sam_no] != NULL) { unsign_8bit_data( funk_sam_ptrs[sam_no],funk_hr_ptr->funk_sb[sam_no].length); set_sample_name(sam_no,filename); } } ferr_val = FERR_OK; if((fp = fopen(filename,"rb")) != NULL) { wav_load_sample_data(); fclose(fp); } else ferr_val = FERR_FOPEN; } /*************************************************************************** * ***************************************************************************/ void load_sample(int sam_no,char *filename,double resamf) { ferr_val = FERR_OK; if(strstr(filename,".snd") != NULL) /*8 bit unsigned .SND*/ snd_load_sample(sam_no,filename,resamf); else if(strstr(filename,".raw") != NULL) /*8 bit unsigned .RAW*/ snd_load_sample(sam_no,filename,resamf); else if(strstr(filename,".wav") != NULL) /*.WAV*/ wav_load_sample(sam_no,filename,resamf); else ferr_val = FERR_SAMUNKNOWN; } /*************************************************************************** **************************************************************************** **************************************************************************** * * LOAD/SAVE .MOD CONVERTER FORMAT (NB/ this is a hack. If you regularly use * this facility, and you know a bit about ANSI C, then finetune the pattern * commands converter, and send me a patch. It's been a VERY long time since * I've tracked with a .MOD tracker, so i'm not really qualified to accurately * finetune it. * * The code you are looking at is basically from the MOD2FNK.PAS program * provided in the DOS32 Funktracker project. * **************************************************************************** **************************************************************************** ***************************************************************************/ #pragma pack(1) /*=MOD STRUCTURES==============================*/ typedef struct { sDB sname[22]; uDW slength; sDB sfinetune; uDB svolume; uDW srepeat; uDW sreplen; } tmodsamples; typedef struct { sDB songname[20]; tmodsamples samples[31]; uDB songlen; uDB restart; uDB sequences[128]; sDB mk[4]; } tmodheader; typedef struct { uDB byte1; uDB byte2; uDB byte3; uDB byte4; } tmodslot; tmodheader modheader; tslot *fnkpat_ptr; tmodslot *modpat_ptr; tmodslot *mod_pattern; #pragma pack() int period_match[61] = { 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,912, 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,0 }; int MOD_tune_table[16] = { (0x369e9a / 428),(0x369e9a / 425),(0x369e9a / 422),(0x369e9a / 419), (0x369e9a / 416),(0x369e9a / 413),(0x369e9a / 410),(0x369e9a / 407), (0x369e9a / 453),(0x369e9a / 450),(0x369e9a / 447),(0x369e9a / 444), (0x369e9a / 441),(0x369e9a / 437),(0x369e9a / 434),(0x369e9a / 431) }; FILE *modfile; int modsam_no; /*************************************************************************** * .MOD LOADER ***************************************************************************/ /*************************************** * ***************************************/ int load_mod_header(void) { register int x,y; char tmp[3]; if(fread(&modheader,sizeof(tmodheader),1,modfile) != 1) { ferr_val = FERR_FREAD; return 0; } if(strncmp(modheader.mk,"M.K.",4) == 0) funk_info.no_active_channels = 4; else if(strncmp(modheader.mk,"FLT4",4) == 0) funk_info.no_active_channels = 4; else if(strncmp(modheader.mk,"FLT8",4) == 0) funk_info.no_active_channels = 8; else if(strncmp(modheader.mk,"6CHN",4) == 0) funk_info.no_active_channels = 6; else if(strncmp(modheader.mk,"8CHN",4) == 0) funk_info.no_active_channels = 8; else if(strncmp(modheader.mk + 2,"CH",2) == 0) { tmp[0] = modheader.mk[0]; tmp[1] = modheader.mk[1]; tmp[2] = 0; sscanf(tmp,"%d",(int *)&(funk_info.no_active_channels)); } else { ferr_val = FERR_FUNK_SIG; return 0; } funk_info.sample_precision = 8; new_funk_module(); funk_hr_ptr->info[2] = FKCARD_RIPPED; for(x = 0;x < modheader.songlen;x++) funk_hr_ptr->order_list[x] = modheader.sequences[x]; for(x = 0;x < 31;x++) { for(y = 0;y < 19;y++) { funk_hr_ptr->funk_sb[x].sname[y] = modheader.samples[x].sname[y]; if(((uDB)funk_hr_ptr->funk_sb[x].sname[y] < ' ') || ((uDB)funk_hr_ptr->funk_sb[x].sname[y] > 127)) funk_hr_ptr->funk_sb[x].sname[y] = ' '; } modheader.samples[x].slength = (((modheader.samples[x].slength & 0xff) << 8) + ((modheader.samples[x].slength & 0xff00) >> 8)) << 1; modheader.samples[x].srepeat = (((modheader.samples[x].srepeat & 0xff) << 8) + ((modheader.samples[x].srepeat & 0xff00) >> 8)) << 1; modheader.samples[x].sreplen = (((modheader.samples[x].sreplen & 0xff) << 8) + ((modheader.samples[x].sreplen & 0xff00) >> 8)) << 1; if(modheader.samples[x].slength > 0) { if(modheader.samples[x].sreplen > 2) { funk_hr_ptr->funk_sb[x].length = modheader.samples[x].srepeat + modheader.samples[x].sreplen; if(funk_hr_ptr->funk_sb[x].length > modheader.samples[x].slength) funk_hr_ptr->funk_sb[x].length = modheader.samples[x].slength; funk_hr_ptr->funk_sb[x].start = modheader.samples[x].srepeat; } else funk_hr_ptr->funk_sb[x].length = modheader.samples[x].slength; } if(modheader.samples[x].svolume > 0) { y = modheader.samples[x].svolume << 2; if(y == 256) y = 255; funk_hr_ptr->funk_sb[x].volume = y; } else funk_hr_ptr->funk_sb[x].volume = 0; } return 1; } /*************************************** * ***************************************/ void load_mod_pattern(void) { register int x,pattern,treks,channels; char oldsample[32]; find_pats_seqs(); for(x = 0;x < 32;x++) oldsample[x] = 0; fnkpat_ptr = funk_pat_ptr; for(pattern = 0;pattern < funk_info.no_of_patterns;pattern++) { if(fread(mod_pattern, (64 * funk_info.no_active_channels * sizeof(mod_pattern)),1,modfile) != 1) { ferr_val = FERR_FREAD; return; } modpat_ptr = mod_pattern; for(treks = 0;treks < 64;treks++) for(channels = 0;channels < funk_info.no_active_channels;channels++) { int period = ((modpat_ptr->byte1 & 0xf) << 8) + modpat_ptr->byte2; int pers,note = 0,sample,command,commval; for(pers = 0;pers < 60;pers++) if(period >= period_match[pers]) { note = pers; break; } sample = (modpat_ptr->byte3 >> 4) | (modpat_ptr->byte1 & 0xf0); command = modpat_ptr->byte3 & 0xf; commval = modpat_ptr->byte4; if(period != 0) { if(sample == 0) sample = oldsample[channels]; else oldsample[channels] = sample; if(sample > 0) { sample--; fnkpat_ptr->not_sam = note << 2; fnkpat_ptr->sam_com = 0xf; fnkpat_ptr->not_sam |= (sample >> 4) & 3; fnkpat_ptr->sam_com |= (sample & 15) << 4; } } if(command > 0) { int fnkcom = 0xf + 'A'; int fnkcomv = 0; int xxx; switch(command) { case 0: /*arpeggio*/ fnkcom = 'L'; fnkcomv = commval; break; case 1: /*portup*/ fnkcom = 'A'; fnkcomv = commval; break; case 2: /*portdn*/ fnkcom = 'B'; fnkcomv = commval; break; case 5: /*porta note + volslide}*/ case 3: /*porta note*/ fnkcom = 'C'; fnkcomv = commval; break; case 6: /*vibrato + volslide*/ case 4: /*vibrato*/ fnkcom = 'D'; fnkcomv = commval; break; case 7: /*tremolo*/ fnkcom = 'K'; fnkcomv = commval; break; case 9: /*sample offset*/ fnkcom = 'M'; fnkcomv = commval; break; case 0xa: /*Volume Slide*/ if((commval & 0xf0) != 0) fnkcom = 'G'; else fnkcom = 'H'; commval &= 0xf; break; case 0xc: /*set volume*/ fnkcom = 'N'; xxx = commval << 2; if(xxx == 256) xxx = 255; fnkcomv = xxx; break; case 0xd: /*pattern break*/ funk_hr_ptr->break_list[pattern] = treks; break; case 0xe: /*command e*/ switch(commval >> 4) { case 1: /*fine slideup*/ fnkcom = 'O'; fnkcomv = 0x40 | (commval & 0xf); break; case 2: /*fine slidedn*/ fnkcom = 'O'; fnkcomv = 0x50 | (commval & 0xf); break; case 4: /*Vibrato waveform cntl*/ fnkcom = 'O'; switch(commval & 0xf) { case 0: fnkcomv = 0x00; break; /*sine*/ case 1: fnkcomv = 0x03; break; /*ramp down*/ case 2: fnkcomv = 0x02; break; /*square*/ case 3: fnkcomv = 0x04; break; /*random*/ } break; case 7: /*tremolo waveform cntl*/ fnkcom = 'O'; switch(commval & 0xf) { case 0: fnkcomv = 0x05; break; /*sine*/ case 1: fnkcomv = 0x08; break; /*ramp down*/ case 2: fnkcomv = 0x07; break; /*square*/ case 3: fnkcomv = 0x09; break; /*random*/ } break; case 9: /*retrig note*/ fnkcom = 'O'; fnkcomv = 0xD0 | (commval & 0xf); break; case 0xa: /*fine volume up*/ fnkcom = 'O'; fnkcomv = 0x60 | (commval & 0xf); break; case 0xb: /*fine volume dn*/ fnkcom = 'O'; fnkcomv = 0x70 | (commval & 0xf); break; case 0xc: /*note cut*/ fnkcom = 'O'; fnkcomv = 0x01 | (commval & 0xf); break; } break; case 0xf: /*set tempo*/ fnkcom = 'O'; if(commval > 0) commval--; fnkcomv = 0xf0 | (commval & 0xf); break; } fnkcom -= 'A'; fnkpat_ptr->sam_com &= 0xf0; fnkpat_ptr->sam_com |= fnkcom & 0xf; fnkpat_ptr->com_val = fnkcomv; } modpat_ptr++; fnkpat_ptr++; } } } /*************************************** * ***************************************/ void load_mod_samples(void) { unsigned long read_length; for(modsam_no = 0;modsam_no < 31;modsam_no++) { if(modheader.samples[modsam_no].slength > 0) { double saminfreqinc = (double)MOD_tune_table[(int)modheader.samples[modsam_no].sfinetune] / (double)MOD_tune_table[0]; if(modheader.samples[modsam_no].sreplen > 2) { read_length = modheader.samples[modsam_no].srepeat + modheader.samples[modsam_no].sreplen; if(read_length >= modheader.samples[modsam_no].slength) { read_length = modheader.samples[modsam_no].slength; funk_sam_ptrs[modsam_no] = load_samdata(modfile,modsam_no,read_length,saminfreqinc,1); if(ferr_val != FERR_OK) return; } else { funk_sam_ptrs[modsam_no] = load_samdata(modfile,modsam_no,read_length,saminfreqinc,1); if(ferr_val != FERR_OK) return; read_length = modheader.samples[modsam_no].slength - (modheader.samples[modsam_no].srepeat + modheader.samples[modsam_no].sreplen); fseek(modfile,read_length,SEEK_CUR); } } else { read_length = modheader.samples[modsam_no].slength; funk_sam_ptrs[modsam_no] = load_samdata(modfile,modsam_no,read_length,saminfreqinc,1); if(ferr_val != FERR_OK) return; } } } } /*************************************** * ***************************************/ void load_mod_module(char *filename) { ferr_val = FERR_OK; if((mod_pattern = malloc(64 * MAXIMUM_CHANNELS * sizeof(mod_pattern))) != NULL) { if((modfile = fopen(filename,"rb")) != NULL) { if(load_mod_header()) { load_mod_pattern(); load_mod_samples(); if(strlen(filename) < 255) strcpy(strstr(filename,".mod"),".Funk"); else strcpy(strstr(filename,".mod") - 1,".Funk"); } fclose(modfile); } else ferr_val = FERR_FOPEN; free(mod_pattern); } else ferr_val = FERR_MALLOC; } /*************************************************************************** * .MOD SAVER ***************************************************************************/ /*************************************** * ***************************************/ int save_mod_header(void) { register int x; char tmp[3]; strncpy(modheader.songname,"Ripped from FnkGOLD",20); for(x = 0;x < 31;x++) { strncpy(modheader.samples[x].sname,funk_hr_ptr->funk_sb[x].sname,19); modheader.samples[x].sfinetune = 0; modheader.samples[x].svolume = funk_hr_ptr->funk_sb[x].volume >> 2; if(funk_hr_ptr->funk_sb[x].length) { register unsigned int length = funk_hr_ptr->funk_sb[x].length >> 1; modheader.samples[x].slength = ((length & 0xff) << 8) + ((length & 0xff00) >> 8); if(funk_hr_ptr->funk_sb[x].start == 0xffffffff) { modheader.samples[x].srepeat = 0; modheader.samples[x].sreplen = 0; } else { register unsigned int replen; register unsigned int start = funk_hr_ptr->funk_sb[x].start >> 1; modheader.samples[x].srepeat = ((start & 0xff) << 8) + ((start & 0xff00) >> 8); replen = (funk_hr_ptr->funk_sb[x].length - funk_hr_ptr->funk_sb[x].start) >> 1; modheader.samples[x].sreplen = ((replen & 0xff) << 8) + ((replen & 0xff00) >> 8); } } else { modheader.samples[x].slength = 0; modheader.samples[x].srepeat = 0; modheader.samples[x].sreplen = 0; } } modheader.songlen = funk_info.no_of_sequences + 1; modheader.restart = funk_hr_ptr->loop_order; for(x = 0;x < 128;x++) if(funk_hr_ptr->order_list[x] == 0xff) modheader.sequences[x] = 0; else modheader.sequences[x] = funk_hr_ptr->order_list[x]; if(funk_info.no_active_channels == 4) strncpy(modheader.mk,"M.K.",4); else if(funk_info.no_active_channels == 6) strncpy(modheader.mk,"6CHN",4); else if(funk_info.no_active_channels == 8) strncpy(modheader.mk,"8CHN",4); else { strncpy(modheader.mk,"00CH",4); sprintf(tmp,"%d",funk_info.no_active_channels); if(funk_info.no_active_channels < 10) { modheader.mk[0] = 0x30; modheader.mk[1] = tmp[0]; } else { modheader.mk[0] = tmp[0]; modheader.mk[1] = tmp[1]; } } if(fwrite(&modheader,sizeof(tmodheader),1,modfile) != 1) { ferr_val = FERR_FWRITE; return 0; } return 1; } /*************************************** * ***************************************/ void save_mod_pattern(void) { register int pattern,treks,channels,old_note, note = 0,sample,commnd,comval,period,modcommnd; fnkpat_ptr = funk_pat_ptr; for(pattern = 0;pattern < funk_info.no_of_patterns;pattern++) { modpat_ptr = mod_pattern; for(treks = 0;treks < 64;treks++) for(channels = 0;channels < funk_info.no_active_channels;channels++) { old_note = note; note = fnkpat_ptr->not_sam >> 2; sample = ((fnkpat_ptr->not_sam & 0x3) << 4) + (fnkpat_ptr->sam_com >> 4) + 1; commnd = fnkpat_ptr->sam_com & 0xf; comval = fnkpat_ptr->com_val; if(note == 0x3f) { modpat_ptr->byte1 = 0; modpat_ptr->byte2 = 0; modpat_ptr->byte3 = 0; } else { if(note == 0x3E) period = period_match[old_note]; else period = period_match[note]; modpat_ptr->byte1 = (sample & 0xf0) | ((period >> 8) & 0x0f); modpat_ptr->byte2 = period & 0xff; modpat_ptr->byte3 = ((sample & 0x0f) << 4); } modcommnd = 0; modpat_ptr->byte4 = 0; switch(commnd) { case 0xd: /*volume*/ modcommnd = 0xc; modpat_ptr->byte4 = comval >> 2; break; case 0xe: /*cmd O*/ switch(comval >> 4) { case 0xf: /*tempo*/ modcommnd = 0xf; modpat_ptr->byte4 = comval & 0xf; break; } break; } modpat_ptr->byte3 |= modcommnd; fnkpat_ptr++; modpat_ptr++; } if(fwrite(mod_pattern, (64 * funk_info.no_active_channels * sizeof(mod_pattern)),1,modfile) != 1) { ferr_val = FERR_FWRITE; return; } } } /*************************************** * ***************************************/ void save_mod_samples(void) { register int x; for(x = 0;x < 31;x++) { register unsigned long new_length = funk_hr_ptr->funk_sb[x].length & 0xfffffffe; if(new_length) if(fwrite(funk_sam_ptrs[x],1,new_length,modfile) != new_length) { ferr_val = FERR_FWRITE; return; } } } /*************************************** * ***************************************/ void save_mod_module(char *filename) { register int x,sample_count; ferr_val = FERR_OK; find_pats_seqs(); if((funk_info.no_of_patterns > 64) || (funk_info.sample_precision == 16) || (funk_info.no_of_sequences > 127)) { /*Funktracker modules are too complex in .MOD format as it is!*/ ferr_val = FERR_MODCOMPLEX; return; } sample_count = 0; for(x = 0;x < 31;x++) if(funk_hr_ptr->funk_sb[x].length) { if(funk_hr_ptr->funk_sb[x].length > 0x1ffff) { ferr_val = FERR_MODCOMPLEX; return; } sample_count++; } if(sample_count > 31) { ferr_val = FERR_MODCOMPLEX; return; } if((mod_pattern = malloc(64 * MAXIMUM_CHANNELS * sizeof(mod_pattern))) != NULL) { char *new_filename; int new_filename_size = strlen(filename) + 4; new_filename = malloc(new_filename_size); if(new_filename != NULL) { memset(new_filename,0,new_filename_size); if(strstr(filename,".Funk") != NULL) strncpy(new_filename,filename,strlen(filename) - 4); else if(strstr(filename,".fnk") != NULL) strncpy(new_filename,filename,strlen(filename) - 3); strcat(new_filename,"mod"); if((modfile = fopen(new_filename,"wb")) != NULL) { if(save_mod_header()) { save_mod_pattern(); save_mod_samples(); } fclose(modfile); } else ferr_val = FERR_FCREATE; free(new_filename); } else ferr_val = FERR_MALLOC; free(mod_pattern); } else ferr_val = FERR_MALLOC; } /*************************************************************************** * N TRACK TO N TRACK CONVERTER * * change the number of channels a song has. * ***************************************************************************/ void save_ntrac_funk_module(char *filename,int new_no_active_channels) { FILE *funk_fp; int x,y,z,old_no_active_channels,trac_c_Len; tslot new_pat_trek[MAXIMUM_CHANNELS]; void convert(void) { if(fwrite(funk_hr_ptr,sizeof(tfunk_hr),1,funk_fp) != 1) { ferr_val = FERR_FWRITE; return; } fnkpat_ptr = funk_pat_ptr; trac_c_Len = old_no_active_channels * sizeof(tslot); for(x = 0;x < funk_info.no_of_patterns;x++) for(y = 0;y < 64;y++) { for(z = 0;z < funk_info.no_active_channels;z++) clear_slot(&new_pat_trek[z]); memcpy(&new_pat_trek,fnkpat_ptr,trac_c_Len); if(fwrite(&new_pat_trek,sizeof(tslot), funk_info.no_active_channels,funk_fp) != funk_info.no_active_channels) { ferr_val = FERR_FWRITE; return; } fnkpat_ptr += old_no_active_channels; } for(x = 0;x < 64;x++) if(funk_hr_ptr->funk_sb[x].length) if(!dsp_save_sample(funk_fp,x)) return; } old_no_active_channels = funk_info.no_active_channels; funk_info.no_active_channels = new_no_active_channels; chg_funk_funktype(); ferr_val = FERR_OK; if(strlen(filename) < 255) strcat(filename,"*"); funk_hr_ptr->LZH_check_size = sizeof(tfunk_hr) + (funk_info.no_of_patterns * 64 * funk_info.no_active_channels * sizeof(tslot)); for(x = 0;x < 64;x++) funk_hr_ptr->LZH_check_size += funk_hr_ptr->funk_sb[x].length * ((funk_hr_ptr->info[3] & 0x1) + 1); funk_fp = fopen(filename,"wb"); if(funk_fp != NULL) { convert(); fclose(funk_fp); } else ferr_val = FERR_FCREATE; dealloc_funk_mem(); } /*************************************************************************** * OPTIMISE FUNK MODULE * * - de-fragment pattern block removing holes/gaps * - removes used tracks * - removes used samples * ***************************************************************************/ void opti_funk_module(char *filename) { register int pattern,treks,channels,frm_channels,x,y; char sample_flag[64]; char track_flag[MAXIMUM_CHANNELS]; #pragma pack(1) uDB order_list[256]; uDB break_list[128]; #pragma pack() tslot *funk_pat_ptr_old; load_funk_module(filename); if(ferr_val == FERR_OLD_FK) ferr_val = FERR_OK; else if(ferr_val != FERR_OK) return; /*find out what's used*/ for(x = 0;x < 64;x++) sample_flag[x] = 0; for(x = 0;x < MAXIMUM_CHANNELS;x++) track_flag[x] = 0; fnkpat_ptr = funk_pat_ptr; for(pattern = 0;pattern < funk_info.no_of_patterns;pattern++) for(treks = 0;treks < 64;treks++) for(channels = 0;channels < funk_info.no_active_channels;channels++) { if(!((fnkpat_ptr->not_sam == 0xfc) && (fnkpat_ptr->sam_com == 0x0f) && (fnkpat_ptr->com_val == 0x00))) track_flag[channels] = 1; if((fnkpat_ptr->not_sam >> 2) != 0x3f) { int sample = ((fnkpat_ptr->not_sam & 0x3) << 4) + (fnkpat_ptr->sam_com >> 4); if(funk_hr_ptr->funk_sb[sample].length) sample_flag[sample] = 1; } fnkpat_ptr++; } /*de-fragment pattern block removing holes/gaps*/ memcpy(&order_list,funk_hr_ptr->order_list,256); memcpy(&break_list,funk_hr_ptr->break_list,128); for(x = 0;x < 256;x++) funk_hr_ptr->order_list[x] = 0xff; for(x = 0;x < 128;x++) funk_hr_ptr->break_list[x] = 0x3f; funk_pat_ptr_old = funk_pat_ptr; ferr_val = alloc_pat_blk(); if(ferr_val == FERR_OK) { register int pat_size = 64 * funk_info.no_active_channels; register int pattern_count = 0; for(x = 0;x <= funk_info.no_of_sequences;x++) { register int c_ol = order_list[x]; if(c_ol != 0xff) { memcpy( funk_pat_ptr + (pat_size * pattern_count), funk_pat_ptr_old + (pat_size * c_ol), pat_size * sizeof(tslot)); for(y = 0;y <= funk_info.no_of_sequences;y++) if(order_list[y] == c_ol) { funk_hr_ptr->order_list[y] = pattern_count; order_list[y] = 0xff; } funk_hr_ptr->break_list[pattern_count] = break_list[c_ol]; pattern_count++; } } free(funk_pat_ptr_old); } else return; find_pats_seqs(); /*removes used tracks*/ y = 0; for(channels = 0;channels < funk_info.no_active_channels;channels++) if(!track_flag[channels]) { if(channels == funk_info.no_active_channels) return; for(frm_channels = (channels + 1); frm_channels < funk_info.no_active_channels;frm_channels++) if(track_flag[frm_channels]) { fnkpat_ptr = funk_pat_ptr + channels; funk_pat_ptr_old = funk_pat_ptr + frm_channels; for(x = 0;x < (funk_info.funk_pd_size * 64);x++) { memcpy(fnkpat_ptr,funk_pat_ptr_old,3); clear_slot(funk_pat_ptr_old); fnkpat_ptr += funk_info.no_active_channels; funk_pat_ptr_old += funk_info.no_active_channels; } track_flag[channels] = 1; track_flag[frm_channels] = 0; y++; break; } } else y++; if(y < 4) y = 4; /*removes used samples*/ for(x = 0;x < 64;x++) { if(!sample_flag[x]) { funk_hr_ptr->funk_sb[x].start = 0xffffffff; funk_hr_ptr->funk_sb[x].length = 0; free(funk_sam_ptrs[x]); funk_sam_ptrs[x] = NULL; } } /*save optimised module*/ save_ntrac_funk_module(filename,y); } /*************************************************************************** * 8 -> 16 -> 8 bit module converter * * to_type : 0 = to 8 bit * 1 = to 16 bit ***************************************************************************/ void convprec_funk_module(char *filename,int to_type) { FILE *funk_fp; int x = 0; long pattern_block_size; void convert(void) { if(fwrite(funk_hr_ptr,sizeof(tfunk_hr),1,funk_fp) != 1) { ferr_val = FERR_FWRITE; return; } if(fwrite(funk_pat_ptr,sizeof(tslot), pattern_block_size,funk_fp) != pattern_block_size) { ferr_val = FERR_FWRITE; return; } for(x = 0;x < 64;x++) if(funk_hr_ptr->funk_sb[x].length) { #pragma pack(1) void *new_sam_ptr; #pragma pack() register unsigned long samsize = funk_hr_ptr->funk_sb[x].length << to_type; register unsigned long samno; if((new_sam_ptr = malloc(samsize)) != NULL) { for(samno = 0;samno < funk_hr_ptr->funk_sb[x].length;samno++) #pragma pack(1) if(to_type == 1) *(sDW *)((sDW *)new_sam_ptr + (unsigned int)samno) = *(sDW *)((sDB *)(funk_sam_ptrs[x]) + samno) << 8; else *((sDB *)new_sam_ptr + samno) = *((sDW *)funk_sam_ptrs[x] + samno) >> 8; #pragma pack() if(fwrite(new_sam_ptr,1,samsize,funk_fp) != samsize) { ferr_val = FERR_FWRITE; return; } free(new_sam_ptr); } else { ferr_val = FERR_MALLOC; return; } } } load_funk_module(filename); if(ferr_val == FERR_OLD_FK) ferr_val = FERR_OK; else if(ferr_val != FERR_OK) return; if(funk_hr_ptr->info[3] & 1) { if(to_type) { ferr_val = FERR_PREC_NN; return; } } else { if(!to_type) { ferr_val = FERR_PREC_NN; return; } } if(strlen(filename) < 255) strcat(filename,"*"); funk_hr_ptr->info[3] = to_type; set_BPM(); chg_funk_funktype(); pattern_block_size = funk_info.no_of_patterns * 64 * funk_info.no_active_channels; funk_hr_ptr->LZH_check_size = sizeof(tfunk_hr) + (pattern_block_size * sizeof(tslot)); for(x = 0;x < 64;x++) funk_hr_ptr->LZH_check_size += funk_hr_ptr->funk_sb[x].length * ((funk_hr_ptr->info[3] & 0x1) + 1); if((funk_fp = fopen(filename,"wb")) != NULL) { convert(); fclose(funk_fp); } else ferr_val = FERR_FCREATE; dealloc_funk_mem(); }