home *** CD-ROM | disk | FTP | other *** search
- /*
- * load_ult.c - Loads Ultratracker modules.
- *
- * (C) 1994 Mikael Nordqvist (d91mn@efd.lth.se, mech@df.lth.se)
- */
-
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <sys/soundcard.h>
- #include <sys/ultrasound.h>
- #include <limits.h>
- #include <string.h>
- #include <ctype.h>
-
- #include "mod.h"
-
- /* External global variables */
-
- SEQ_DECLAREBUF();
- extern int seqfd, gus_dev;
-
- extern struct mod_info M;
- extern struct options opt;
-
- extern char quit;
-
- extern char effect_used[NR_EFX];
-
- /* Local functions */
- static int process_header(int);
- static int read_patterndata(int);
- static void fix_effect(unsigned char *, unsigned char *);
-
- /* Defines and variables used while loading module */
-
- #define ULT_OFFSET_MAGIC 0
- #define ULT_OFFSET_NAME 15
- #define ULT_OFFSET_SONGTEXTLEN 47
- #define ULT_OFFSET_SONGTEXT 48
-
- #define ULT_SAMPLEINFO_SIZE 64
- #define ULT_SAMPLEINFO_SIZE_NEW 66
-
- #define ULT_FLAG_BITS_16 4
- #define ULT_FLAG_LOOP 8
- #define ULT_FLAG_LOOPBACKWARD 16
-
- #define ULT_REPEATBLOCK_NOTE 0xfc
-
- static int expected_length, version;
-
- int load_ult(int fd)
- {
- char tmpbuf[80];
-
- int i, diff, fatalerr;
-
- print_status("Loading ULT");
- M.nr_tracks=0;
- if(!process_header(fd))
- return 0;
-
- if(!read_patterndata(fd)) {
- info("Unable to read patterndata.\n");
- return 0;
- }
-
- ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev);
-
- info("\nUploading instruments to GUS...\n");
-
- fatalerr=0;
- for(i=1; i <= M.nr_samples; ++i) {
- if(M.sample[i].length > 4) { /* Only load non-silent samples */
- if(!read_and_upload_sample(fd, i)) {
- fatalerr=1;
- break;
- }
- }
- else { /* Skip sample */
- if(lseek(fd, M.sample[i].length, SEEK_CUR) == -1){
- fatalerr=1;
- break;
- }
- }
- if(quit == QUIT_SIGNAL) /* Bail out if we got QUIT_SIGNAL */
- return 0;
- }
-
- if(fatalerr) {
- diff=expected_length-lseek(fd, 0, SEEK_CUR);
- sprintf(tmpbuf, "File %d bytes short", diff);
- print_status(tmpbuf);
- info("\nShort file (%d bytes missing).\n",0);
- sleep(1);
- return 0;
- }
-
- /* Check if filelength was as expected. This is done with two
- * statements to make sure we don't move the filepointer to the
- * end before checking current position.
- */
-
- diff=-lseek(fd, 0, SEEK_CUR);
- diff+=lseek(fd, 0, SEEK_END);
-
- if(diff && opt.verbose) {
- warning("\nFound %d garbagebytes after samples. Ignoring.\n", diff);
- }
-
- print_songname(M.name);
- print_samples(1);
- print_songinfo(M.nr_voices, M.nr_samples, "ULT", expected_length,
- M.songlength, M.nr_patterns);
- return 1;
- }
-
-
- static int process_header(int fd)
- {
- unsigned char buf[32*255+1]; /* Maximum size of SONGTEXT */
- char *p;
- int tmp, i, current_si_size;
- struct sample_info *s;
-
- if(read(fd, buf, ULT_OFFSET_SONGTEXT) != ULT_OFFSET_SONGTEXT) {
- info("Unable to read header from file.\n");
- return 0;
- }
-
- expected_length=ULT_OFFSET_SONGTEXT; /* Start counting expected filesize */
-
- if(strncmp("MAS_UTrack_V", &buf[ULT_OFFSET_MAGIC], 12)) {
- info("Not an Ultratracker module.\n");
- return 0;
- }
-
- /* Copy songname and strip trailing spaces */
- strncpy(M.name, &buf[ULT_OFFSET_NAME], 32);
- M.name[32]=0;
- fix_string(M.name);
-
- buf[ULT_OFFSET_MAGIC+15]=0;
- version=atoi(&buf[ULT_OFFSET_MAGIC+12]);
- if(version < 1 || version >4) {
- print_status("Format not supported");
- info("Format version '%s' not supported.\n", &buf[ULT_OFFSET_MAGIC]);
- return 0;
- }
-
- info("Format version '%s'.\n", &buf[ULT_OFFSET_MAGIC]);
-
- i=32*buf[ULT_OFFSET_SONGTEXTLEN];
- if(version >= 2 && i) {
- M.songtext=(void *)malloc(i+1);
- if(read(fd, M.songtext, i) != i) {
- info("Unable to load songtext.\n");
- return 0;
- }
- *(M.songtext+i)=0;
- fix_string(M.songtext);
- expected_length+=i;
- }
- else
- M.songtext=0;
-
- if(M.songtext && opt.verbose) {
- printf("\n---------- Message: ----------\n");
- i=strlen(M.songtext);
- tmp=0;
- while(tmp < i) {
- printf("%.32s\n", &M.songtext[tmp]);
- tmp+=32;
- }
- printf("\n------------------------------\n");
- }
-
- if(read(fd, buf, 1) != 1) {
- info("Unable to read header from file.\n");
- return 0;
- }
- M.nr_samples=(unsigned char)buf[0];
- expected_length++;
-
- if(!M.nr_samples || M.nr_samples > 127) {
- info("Invalid number of samples in module.\n");
- return 0;
- }
-
- if(version >= 2) { /* Linear volumes */
- }
- else { /* LOG volumes */
- info("Logarithmic volumes not supported (yet). Might sound"
- " a bit strange.\n");
- }
-
- M.sample=(struct sample_info *)malloc((1+M.nr_samples)*
- sizeof(struct sample_info));
-
- current_si_size=(version < 4 ? ULT_SAMPLEINFO_SIZE :
- ULT_SAMPLEINFO_SIZE_NEW);
-
- expected_length+=M.nr_samples*current_si_size;
- print_sample_info_header();
-
- for(i=1; i <= M.nr_samples; ++i) {
- if(read(fd, buf, current_si_size) != current_si_size) {
- info("Unable to read sampleheader (%d).\n", i);
- return 0;
- }
- p=buf;
-
- s=&M.sample[i];
- s->valid=0; /* Valid isn't set to TRUE until it's
- * sampledata has been read.
- */
- strncpy(s->name, p, 32);
- s->name[32]=0;
- p+=32;
- fix_string(s->name);
-
- strncpy(s->dosname, p, 12);
- s->dosname[12]=0;
- p+=12;
- fix_string(s->dosname);
-
- s->repeat_start=*(unsigned long *)p; p+=4;
- s->repeat_end=*(unsigned long *)p; p+=4;
- tmp=*(unsigned long *)p; p+=4;
- s->length=*(unsigned long *)p-tmp; p+=4;
-
- s->volume=*(unsigned char *)p++;
- tmp=*(unsigned char *)p++; /* Flags */
-
- if(tmp&ULT_FLAG_BITS_16) {
- s->length*=2;
- s->bits_16=1;
- }
- else
- s->bits_16=0;
-
- s->unsigned_data=0;
-
- if(tmp&ULT_FLAG_LOOP) {
- if(tmp&ULT_FLAG_LOOPBACKWARD)
- s->looped=LOOP_BIDIR;
- else
- s->looped=LOOP_FORWARD;
- }
- else
- s->looped=0;
-
- /* The docs say finetune comes before c2freq, but that isn't
- * the case with the included "cybocult.ult" so...
- */
- if(version >= 4) {
- s->c2freq=*(short *)p;
- p+=2;
- }
- else
- s->c2freq=-1; /* Use PAL/NTSC */
-
- s->finetune=(*(short *)p)/4096; /* Approximate FT */
- p+=2;
-
- s->repeat_start=
- MIN(MAX(0, s->repeat_start), s->length-2);
-
- /* Is this one including/excluding the last sample? */
- s->repeat_end=
- MIN(MAX(0, s->repeat_end), s->length-2);
-
- expected_length+=s->length;
-
- print_sample_info(i);
- }
-
- if(read(fd, buf, 258) != 258) {
- info("Unable to load patterntable.\n");
- return 0;
- }
- expected_length+=258;
-
- memcpy(M.patterntable, buf, 256);
- M.nr_voices=buf[256]+1;
- M.nr_patterns=buf[257]+1;
-
- for(i=0; i < 256; ++i)
- if(M.patterntable[i] >= M.nr_patterns)
- break;
- M.songlength=i;
-
- if(M.nr_voices > 32 || M.nr_voices <= 0) {
- info("Illegal number of voices (%d).\n", M.nr_voices);
- return 0;
- }
-
- if(version >= 3) {
- if(read(fd, M.panning, M.nr_voices) != M.nr_voices) {
- info("Unable to load PAN-position table.\n");
- return 0;
- }
- for(tmp=0; tmp < M.nr_voices; ++tmp)
- M.panning[tmp]&=0x0f;
- expected_length+=M.nr_voices;
- }
- else {
- for(tmp=0; tmp < M.nr_voices; ++tmp)
- M.panning[tmp]=get_voice_balance(tmp);
- }
-
- M.restartpos=0;
- M.volrange=255;
-
- info("\nVoices: %d Patterns: %d Songlength: %d\n",
- M.nr_voices, M.nr_patterns, M.songlength);
-
- return 1;
- }
-
-
- static int read_patterndata(int fd)
- {
- unsigned char buf[7];
- unsigned short effect, arg;
- struct event *e;
- int p, l, v, repeat;
- struct event events[64];
-
- for(v=0; v < NR_EFX; ++v)
- effect_used[v]=0;
-
- for(v=0; v < M.nr_voices; ++v)
- M.track_idx[v]=(int *)malloc(M.nr_patterns*sizeof(int));
-
- /* Allocate for worst case (no identical tracks) */
- M.tracks=(struct event **)malloc(M.nr_patterns*M.nr_voices*
- sizeof(struct event *));
-
- if(!get_bytes(fd, 0, 0))
- return 0;
-
- for(v=0; v < M.nr_voices; ++v) {
- for(p=0; p < M.nr_patterns; ++p) {
- l=0;
- while(l < 64) {
- if(!get_bytes(fd, buf, 5))
- return 0;
- expected_length+=5;
- if(buf[0] == ULT_REPEATBLOCK_NOTE) {
- repeat=buf[1];
- buf[0]=buf[2];
- buf[1]=buf[3];
- buf[2]=buf[4];
- if(!get_bytes(fd, &buf[3], 2))
- return 0;
- expected_length+=2;
- }
- else
- repeat=1;
-
- if(!repeat)
- info("Repeat block with length 0 detected in "
- "pattern %d.\n", p);
-
- while(repeat > 0 && l < 64) {
- e=&events[l];
- e->note=
- (buf[0] ? buf[0]+BASE_NOTE + 2*12: 0); /* X-2 => X-4 */
- e->sample=buf[1];
- arg=*((unsigned short *)&buf[3]);
-
- effect=(buf[2]>>4)&0x0f; /* First effect */
-
- if(effect != 0x0e) {
- e->arg=(arg>>8)&0xff;
- }
- else {
- effect=0x10|((arg>>12)&0x0f);
- e->arg=(arg>>8)&0x0f;
- }
- e->effect=effect;
- fix_effect(&e->effect, &e->arg);
-
- if(e->effect || e->arg)
- effect_used[e->effect]=1;
-
- effect=buf[2]&0x0f; /* Second effect */
-
- if(effect != 0x0e) {
- e->arg2=arg&0xff;
- }
- else {
- effect=0x10|((arg>>4)&0x0f);
- e->arg2=arg&0x0f;
- }
- e->effect2=effect;
- fix_effect(&e->effect2, &e->arg2);
-
- if(e->effect2 || e->arg2)
- effect_used[e->effect2]=1;
-
- --repeat;
- ++l;
- }
- if(repeat)
- info("Repeat block reached outside pattern %d.\n", p);
- }
- M.track_idx[v][p]=get_track_idx(events);
- }
- }
- get_bytes(fd, 0, -1);
-
- /* Octaves 2-9 (0-7) allowed */
- opt.low_note=BASE_NOTE+2*12;
- opt.high_note=BASE_NOTE+10*12-1;
-
- print_used_effects();
-
- return 1;
- }
-
- /* Converts the Ultratracker effects to those used by the playrouting (a
- * set of effects containing all effects in the supported module-formats).
- */
-
- static void fix_effect(unsigned char *effect, unsigned char *arg)
- {
- switch(*effect) {
- case EFX_PORTAUP: /* Effects compatible with PT */
- case EFX_PORTADOWN:
- case EFX_PORTANOTE:
- case EFX_VIBRATO:
- case EFX_VOLSLIDE:
- case EFX_VOLUME:
- case EFX_BREAK:
- case EFX_FINEPORTAUP:
- case EFX_FINEPORTADOWN:
- case EFX_RETRIGGER:
- case EFX_FINEVOLSLIDEUP:
- case EFX_FINEVOLSLIDEDOWN:
- case EFX_NOTECUT:
- case EFX_NOTEDELAY:
- case EFX_PTSPEED:
- break;
-
- /* Effects introduced in 1.5 */
- case EFX_ARPEGGIO:
- if(version < 3)
- *effect=*arg=0;
- break;
-
- /* Effects introduced in 1.6 */
- case EFX_TREMOLO:
- case EFX_SAMPLEOFFSET: /* The '99' SO-effect is handled in effects.c */
- if(version < 4)
- *effect=*arg=0;
- else {
- if(*effect == EFX_SAMPLEOFFSET)
- *effect=EFX_SAMPLEOFFSET_ULT;
- }
- break;
- case EFX_UNUSED2: /* ULT: Patterndelay */
- if(version < 4)
- *effect=*arg=0;
- else
- *effect=EFX_PATTERNDELAY;
- break;
-
-
- /* Special ULT-effects */
- case EFX_JUMP: /* ULT: Balance */
- *effect=EFX_BALANCE;
- break;
- case EFX_FILTER: /* ULT: Set vibrato "strength" (depth?)
- * Not sure if this is correct...
- */
- *effect=EFX_VIBDEPTH;
- break;
-
- #if 0
- /* These effects are not supported by Ultratracker */
- case EFX_PORTANOTEVOLSLIDE: /* ULT: Special - not supported */
- case EFX_VIBRATOVOLSLIDE: /* Not supported */
- case EFX_GLISSANDO:
- case EFX_VIBWAVEFORM:
- case EFX_LOOP:
- case EFX_TREMWAVEFORM:
- #endif
- default:
- *effect=*arg=0;
- }
- }
-