Example #1
0
static void free_instrument(Instrument *ip)
{
	Sample *sp;
	int i;
	if (!ip) return;
	for (i=0; i<ip->samples; i++)
	{
		sp=&(ip->sample[i]);
		Real_Tim_Free(sp->data);
	}
	Real_Tim_Free(ip->sample);
	Real_Tim_Free(ip);
}
Example #2
0
static void free_bank(int dr, int b)
{
	int i;
	ToneBank *bank=((dr) ? drumset[b] : tonebank[b]);
	for (i=0; i<128; i++) {
		if (bank->tone[i].instrument)
		{
			/* Not that this could ever happen, of course */
			if (bank->tone[i].instrument != MAGIC_LOAD_INSTRUMENT)
				free_instrument(bank->tone[i].instrument);
			bank->tone[i].instrument=0;
		}
		if (bank->tone[i].name)
		{
			Real_Tim_Free( bank->tone[i].name );
			bank->tone[i].name = NULL;
		}
	}
}
Example #3
0
static int read_config_file(const char *name)
{
	idFile *  fp;
	char *w[MAXWORDS], *cp;
	ToneBank *bank=0;
	int i, j, k, line=0, words;
	static int rcf_count=0;

	if (rcf_count>50)
	{
		ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
			"Probable source loop in configuration files");
		return (-1);
	}

	if (!(fp=open_file(name, 1, OF_VERBOSE)))
		return -2;
	
	char tokTmp[1024];

	while ( Gets( *fp, tokTmp, 1024 ) )
	{
		
		line++;
		w[words=0]=strtok(tokTmp, " \t\r\n\240");
		if (!w[0] || (*w[0]=='#')) continue;
		while (w[words] && (words < MAXWORDS))
			w[++words]=strtok(0," \t\r\n\240");
		if (!strcmp(w[0], "dir"))
		{
			if (words < 2)
			{
				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
					"%s: line %d: No directory given\n", name, line);
				return -3;
			}
			for (i=1; i<words; i++)
				add_to_pathlist(w[i]);
		}
		else if (!strcmp(w[0], "source"))
		{
			if (words < 2)
			{
				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
					"%s: line %d: No file name given\n", name, line);
				return -4;
			}
			for (i=1; i<words; i++)
			{
				rcf_count++;
				read_config_file(w[i]);
				rcf_count--;
			}
		}
		else if (!strcmp(w[0], "default"))
		{
			if (words != 2)
			{
				ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
					"%s: line %d: Must specify exactly one patch name\n",
					name, line);
				return -5;
			}
			strncpy(def_instr_name, w[1], 255);
			def_instr_name[255]='\0';
		}
		else if (!strcmp(w[0], "drumset"))
		{
			if (words < 2)
			{
				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
					"%s: line %d: No drum set number given\n", 
					name, line);
				return -6;
			}
			i=atoi(w[1]);
			if (i<0 || i>127)
			{
				ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
					"%s: line %d: Drum set must be between 0 and 127\n",
					name, line);
				return -7;
			}
			if (!drumset[i])
			{
				drumset[i]=(ToneBank*)safe_malloc(sizeof(ToneBank));
				memset(drumset[i], 0, sizeof(ToneBank));
			}
			bank=drumset[i];
		}
		else if (!strcmp(w[0], "bank"))
		{
			if (words < 2)
			{
				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
					"%s: line %d: No bank number given\n", 
					name, line);
				return -8;
			}
			i=atoi(w[1]);
			if (i<0 || i>127)
			{
				ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
					"%s: line %d: Tone bank must be between 0 and 127\n",
					name, line);
				return -9;
			}
			if (!tonebank[i])
			{
				tonebank[i]=(ToneBank*)safe_malloc(sizeof(ToneBank));
				memset(tonebank[i], 0, sizeof(ToneBank));
			}
			bank=tonebank[i];
		}
		else {
			if ((words < 2) || (*w[0] < '0' || *w[0] > '9'))
			{
				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
					"%s: line %d: syntax error\n", name, line);
				return -10;
			}
			i=atoi(w[0]);
			if (i<0 || i>127)
			{
				ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
					"%s: line %d: Program must be between 0 and 127\n",
					name, line);
				return -11;
			}
			if (!bank)
			{
				ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
					"%s: line %d: Must specify tone bank or drum set "
					"before assignment\n",
					name, line);
				return -12;
			}
			if (bank->tone[i].name)
				Real_Tim_Free(bank->tone[i].name);
			strcpy((bank->tone[i].name=(char*)safe_malloc(strlen(w[1])+1)),w[1]);
			bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan=
				bank->tone[i].strip_loop=bank->tone[i].strip_envelope=
				bank->tone[i].strip_tail=-1;

			for (j=2; j<words; j++)
			{
				if (!(cp=strchr(w[j], '=')))
				{
					ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: line %d: bad patch option %s\n",
						name, line, w[j]);
					return -13;
				}
				*cp++=0;
				if (!strcmp(w[j], "amp"))
				{
					k=atoi(cp);
					if ((k<0 || k>MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9'))
					{
						ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
							"%s: line %d: amplification must be between "
							"0 and %d\n", name, line, MAX_AMPLIFICATION);
						return -14;
					}
					bank->tone[i].amp=k;
				}
				else if (!strcmp(w[j], "note"))
				{
					k=atoi(cp);
					if ((k<0 || k>127) || (*cp < '0' || *cp > '9'))
					{
						ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
							"%s: line %d: note must be between 0 and 127\n",
							name, line);
						return -15;
					}
					bank->tone[i].note=k;
				}
				else if (!strcmp(w[j], "pan"))
				{
					if (!strcmp(cp, "center"))
						k=64;
					else if (!strcmp(cp, "left"))
						k=0;
					else if (!strcmp(cp, "right"))
						k=127;
					else
						k=((atoi(cp)+100) * 100) / 157;
					if ((k<0 || k>127) ||
						(k==0 && *cp!='-' && (*cp < '0' || *cp > '9')))
					{
						ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
							"%s: line %d: panning must be left, right, "
							"center, or between -100 and 100\n",
							name, line);
						return -16;
					}
					bank->tone[i].pan=k;
				}
				else if (!strcmp(w[j], "keep"))
				{
					if (!strcmp(cp, "env"))
						bank->tone[i].strip_envelope=0;
					else if (!strcmp(cp, "loop"))
						bank->tone[i].strip_loop=0;
					else
					{
						ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
							"%s: line %d: keep must be env or loop\n", name, line);
						return -17;
					}
				}
				else if (!strcmp(w[j], "strip"))
				{
					if (!strcmp(cp, "env"))
						bank->tone[i].strip_envelope=1;
					else if (!strcmp(cp, "loop"))
						bank->tone[i].strip_loop=1;
					else if (!strcmp(cp, "tail"))
						bank->tone[i].strip_tail=1;
					else
					{
						ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
							"%s: line %d: strip must be env, loop, or tail\n",
							name, line);
						return -18;
					}
				}
				else
				{
					ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: line %d: bad patch option %s\n",
						name, line, w[j]);
					return -19;
				}
			}
		}
	}
	if ( fp == 0 ) //(ferror(fp))
	{
		ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't read from %s\n", name);
		close_file(fp);
		return -20;
	}
	close_file(fp);
	return 0;
}
Example #4
0
/* 
If panning or note_to_use != -1, it will be used for all samples,
instead of the sample-specific values in the instrument file. 

For note_to_use, any value <0 or >127 will be forced to 0.

For other parameters, 1 means yes, 0 means no, other values are
undefined.

TODO: do reverse loops right */
static Instrument *load_instrument(char *name, int percussion,
								   int panning, int amp, int note_to_use,
								   int strip_loop, int strip_envelope,
								   int strip_tail)
{
	Instrument *ip;
	Sample *sp;
	idFile * fp;
	uint8_t tmp[1024];
	int i,j,noluck=0;
	char *path;
	char filename[1024];
#ifdef PATCH_EXT_LIST
	static char *patch_ext[] = PATCH_EXT_LIST;
#endif

	if (!name) return 0;

	path = "classicmusic/instruments/";

	idStr instName = name;
	instName.ToUpper();

	strcpy( filename, path );
	strcat( filename, instName.c_str() );
	strcat( filename, ".PAT" );

	/* Open patch file */
	if ((fp=open_file(filename, 1, OF_VERBOSE)) == NULL)
	{
		noluck=1;
#ifdef PATCH_EXT_LIST
		/* Try with various extensions */
		for (i=0; patch_ext[i]; i++)
		{
			if (strlen(name)+strlen(patch_ext[i])<1024)
			{
				strcpy(filename, path);
				strcat(filename, name);
				strcat(filename, patch_ext[i]);
				if ((fp=open_file(filename, 1, OF_VERBOSE)) != NULL)
				{
					noluck=0;
					break;
				}
			}
		}
#endif
	}

	if (noluck)
	{
		ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
			"Instrument `%s' can't be found.", name);
		return 0;
	}

	ctl->cmsg(CMSG_INFO, VERB_NOISY, "Loading instrument %s", current_filename);

	/* Read some headers and do cursory sanity checks. There are loads
	of magic offsets. This could be rewritten... */

	if ((239 != fp->Read(tmp, 239)) ||
		(memcmp(tmp, "GF1PATCH110\0ID#000002", 22) &&
		memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) /* don't know what the
													differences are */
	{
		ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: not an instrument", name);
		return 0;
	}

	if (tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers, 
									  0 means 1 */
	{
		ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
			"Can't handle patches with %d instruments", tmp[82]);
		return 0;
	}

	if (tmp[151] != 1 && tmp[151] != 0) /* layers. What's a layer? */
	{
		ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
			"Can't handle instruments with %d layers", tmp[151]);
		return 0;
	}

	ip=(Instrument *)safe_malloc(sizeof(Instrument));
	ip->samples = tmp[198];
	ip->sample = (Sample *)safe_malloc(sizeof(Sample) * ip->samples);
	for (i=0; i<ip->samples; i++)
	{

		uint8_t fractions;
		 int32_t tmplong;
		uint16_t tmpshort;
		uint8_t tmpchar;

#define READ_CHAR(thing) \
	if (1 != fp->Read(&tmpchar, 1)) goto fail; \
	thing = tmpchar;
#define READ_SHORT(thing) \
	if (2 != fp->Read(&tmpshort, 2 )) goto fail; \
	thing = LE_SHORT(tmpshort);
#define READ_LONG(thing) \
	if (4 != fp->Read(&tmplong, 4 )) goto fail; \
	thing = LE_LONG(tmplong);

		skip(fp, 7); /* Skip the wave name */

		if (1 != fp->Read(&fractions, 1 ))
		{
fail:
			ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Error reading sample %d", i);
			for (j=0; j<i; j++)
				Real_Tim_Free(ip->sample[j].data);
			Real_Tim_Free(ip->sample);
			Real_Tim_Free(ip);
			return 0;
		}

		sp=&(ip->sample[i]);

		READ_LONG(sp->data_length);
		READ_LONG(sp->loop_start);
		READ_LONG(sp->loop_end);
		READ_SHORT(sp->sample_rate);
		READ_LONG(sp->low_freq);
		READ_LONG(sp->high_freq);
		READ_LONG(sp->root_freq);
		skip(fp, 2); /* Why have a "root frequency" and then "tuning"?? */

		READ_CHAR(tmp[0]);

		if (panning==-1)
			sp->panning = (tmp[0] * 8 + 4) & 0x7f;
		else
			sp->panning=(uint8)(panning & 0x7F);

		/* envelope, tremolo, and vibrato */
		if (18 != fp->Read(tmp, 18)) goto fail; 

		if (!tmp[13] || !tmp[14])
		{
			sp->tremolo_sweep_increment=
				sp->tremolo_phase_increment=sp->tremolo_depth=0;
			ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * no tremolo");
		}
		else
		{
			sp->tremolo_sweep_increment=convert_tremolo_sweep(tmp[12]);
			sp->tremolo_phase_increment=convert_tremolo_rate(tmp[13]);
			sp->tremolo_depth=tmp[14];
			ctl->cmsg(CMSG_INFO, VERB_DEBUG,
				" * tremolo: sweep %d, phase %d, depth %d",
				sp->tremolo_sweep_increment, sp->tremolo_phase_increment,
				sp->tremolo_depth);
		}

		if (!tmp[16] || !tmp[17])
		{
			sp->vibrato_sweep_increment=
				sp->vibrato_control_ratio=sp->vibrato_depth=0;
			ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * no vibrato");
		}
		else
		{
			sp->vibrato_control_ratio=convert_vibrato_rate(tmp[16]);
			sp->vibrato_sweep_increment=
				convert_vibrato_sweep(tmp[15], sp->vibrato_control_ratio);
			sp->vibrato_depth=tmp[17];
			ctl->cmsg(CMSG_INFO, VERB_DEBUG,
				" * vibrato: sweep %d, ctl %d, depth %d",
				sp->vibrato_sweep_increment, sp->vibrato_control_ratio,
				sp->vibrato_depth);

		}

		READ_CHAR(sp->modes);

		skip(fp, 40); /* skip the useless scale frequency, scale factor
					  (what's it mean?), and reserved space */

		/* Mark this as a fixed-pitch instrument if such a deed is desired. */
		if (note_to_use!=-1)
			sp->note_to_use=(uint8)(note_to_use);
		else
			sp->note_to_use=0;

		/* seashore.pat in the Midia patch set has no Sustain. I don't
		understand why, and fixing it by adding the Sustain flag to
		all looped patches probably breaks something else. We do it
		anyway. */

		if (sp->modes & MODES_LOOPING) 
			sp->modes |= MODES_SUSTAIN;

		/* Strip any loops and envelopes we're permitted to */
		if ((strip_loop==1) && 
			(sp->modes & (MODES_SUSTAIN | MODES_LOOPING | 
			MODES_PINGPONG | MODES_REVERSE)))
		{
			ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Removing loop and/or sustain");
			sp->modes &=~(MODES_SUSTAIN | MODES_LOOPING | 
				MODES_PINGPONG | MODES_REVERSE);
		}

		if (strip_envelope==1)
		{
			if (sp->modes & MODES_ENVELOPE)
				ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Removing envelope");
			sp->modes &= ~MODES_ENVELOPE;
		}
		else if (strip_envelope != 0)
		{
			/* Have to make a guess. */
			if (!(sp->modes & (MODES_LOOPING | MODES_PINGPONG | MODES_REVERSE)))
			{
				/* No loop? Then what's there to sustain? No envelope needed
				either... */
				sp->modes &= ~(MODES_SUSTAIN|MODES_ENVELOPE);
				ctl->cmsg(CMSG_INFO, VERB_DEBUG, 
					" - No loop, removing sustain and envelope");
			}
			else if (!memcmp(tmp, "??????", 6) || tmp[11] >= 100) 
			{
				/* Envelope rates all maxed out? Envelope end at a high "offset"?
				That's a weird envelope. Take it out. */
				sp->modes &= ~MODES_ENVELOPE;
				ctl->cmsg(CMSG_INFO, VERB_DEBUG, 
					" - Weirdness, removing envelope");
			}
			else if (!(sp->modes & MODES_SUSTAIN))
			{
				/* No sustain? Then no envelope.  I don't know if this is
				justified, but patches without sustain usually don't need the
				envelope either... at least the Gravis ones. They're mostly
				drums.  I think. */
				sp->modes &= ~MODES_ENVELOPE;
				ctl->cmsg(CMSG_INFO, VERB_DEBUG, 
					" - No sustain, removing envelope");
			}
		}

		for (j=0; j<6; j++)
		{
			sp->envelope_rate[j]=
				convert_envelope_rate(tmp[j]);
			sp->envelope_offset[j]= 
				convert_envelope_offset(tmp[6+j]);
		}

		/* Then read the sample data */
		sp->data = (sample_t*)safe_malloc(sp->data_length + 2*sizeof(uint16_t));
		if ( static_cast< size_t >( sp->data_length ) != fp->Read(sp->data, sp->data_length ))
			goto fail;

		if (!(sp->modes & MODES_16BIT)) /* convert to 16-bit data */
		{
			 int32_t i=sp->data_length;
			uint8_t *cp=(uint8_t *)(sp->data);
			uint16_t *tmp,*anew;
			tmp=anew=(uint16*)safe_malloc(sp->data_length*2);
			while (i--)
				*tmp++ = (uint16)(*cp++) << 8;
			cp=(uint8_t *)(sp->data);
			sp->data = (sample_t *)anew;
			Real_Tim_Free(cp);
			sp->data_length *= 2;
			sp->loop_start *= 2;
			sp->loop_end *= 2;
		}
#ifndef LITTLE_ENDIAN
		else
			/* convert to machine byte order */
		{
			 int32_t i=sp->data_length/2;
			int16_t *tmp=(int16_t *)sp->data,s;
			while (i--)
			{ 
				s=LE_SHORT(*tmp);
				*tmp++=s;
			}
		}
#endif

		if (sp->modes & MODES_UNSIGNED) /* convert to signed data */
		{
			 int32_t i=sp->data_length/2;
			int16_t *tmp=(int16_t *)sp->data;
			while (i--)
				*tmp++ ^= 0x8000;
		}

		/* Reverse reverse loops and pass them off as normal loops */
		if (sp->modes & MODES_REVERSE)
		{
			 int32_t t;
			/* The GUS apparently plays reverse loops by reversing the
			whole sample. We do the same because the GUS does not SUCK. */

			ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Reverse loop in %s", name);
			reverse_data((int16_t *)sp->data, 0, sp->data_length/2);

			t=sp->loop_start;
			sp->loop_start=sp->data_length - sp->loop_end;
			sp->loop_end=sp->data_length - t;

			sp->modes &= ~MODES_REVERSE;
			sp->modes |= MODES_LOOPING; /* just in case */
		}

		/* If necessary do some anti-aliasing filtering  */

		if (antialiasing_allowed)
			antialiasing(sp,play_mode->rate);

#ifdef ADJUST_SAMPLE_VOLUMES
		if (amp!=-1)
			sp->volume=(float)((amp) / 100.0);
		else
		{
			/* Try to determine a volume scaling factor for the sample.
			This is a very crude adjustment, but things sound more
			balanced with it. Still, this should be a runtime option. */
			 int32_t i=sp->data_length/2;
			int16_t maxamp=0,a;
			int16_t *tmp=(int16_t *)sp->data;
			while (i--)
			{
				a=*tmp++;
				if (a<0) a=-a;
				if (a>maxamp)
					maxamp=a;
			}
			sp->volume=(float)(32768.0 / maxamp);
			ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * volume comp: %f", sp->volume);
		}
#else
		if (amp!=-1)
			sp->volume=(double)(amp) / 100.0;
		else
			sp->volume=1.0;
#endif

		sp->data_length /= 2; /* These are in bytes. Convert into samples. */
		sp->loop_start /= 2;
		sp->loop_end /= 2;


		/* The sample must be padded out by 2 extra sample, so that
		round off errors in the offsets used in interpolation will not
		cause a "pop" by reading random data beyond data_length */
		sp->data[sp->data_length] = sp->data[sp->data_length + 1] = 0;

		/* Then fractional samples */
		sp->data_length <<= FRACTION_BITS;
		sp->loop_start <<= FRACTION_BITS;
		sp->loop_end <<= FRACTION_BITS;

		/* Adjust for fractional loop points. This is a guess. Does anyone
		know what "fractions" really stands for? */

		/* Seems harmless: the Doom samples with loop-points closest
		to data-length do not have fractions. */
		sp->loop_start |=
			(fractions & 0x0F) << (FRACTION_BITS-4);
		sp->loop_end |=
			((fractions>>4) & 0x0F) << (FRACTION_BITS-4);

		/* If this instrument will always be played on the same note,
		and it's not looped, we can resample it now. */
		if (sp->note_to_use && !(sp->modes & MODES_LOOPING))
			pre_resample(sp);

#ifdef LOOKUP_HACK
		/* Squash the 16-bit data into 8 bits. */
		{
			uint8_t *gulp,*ulp;
			int16_t *swp;
			int l=sp->data_length >> FRACTION_BITS;
			gulp=ulp=safe_malloc(l+1);
			swp=(int16_t *)sp->data;
			while(l--)
				*ulp++ = (*swp++ >> 8) & 0xFF;
			Real_Tim_Free(sp->data);
			sp->data=(sample_t *)gulp;
		}
#endif

		if (strip_tail==1)
		{
			/* Let's not really, just say we did. */
			ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Stripping tail");
			sp->data_length = sp->loop_end;
		}
	}

	delete fp;

	return ip;
}