home *** CD-ROM | disk | FTP | other *** search
- /*
- * sample.c - Functions for handling samples.
- *
- * (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 <sys/ioctl.h>
- #include <sys/soundcard.h>
- #include <sys/ultrasound.h>
- #include <limits.h>
-
- #include "mod.h"
-
- /* External global variables */
-
- SEQ_DECLAREBUF();
- extern int seqfd, gus_dev;
-
- extern struct mod_info M;
- extern struct options opt;
-
- int read_and_upload_sample(int fd, int i)
- {
- int t, delta, base, skip, span, origlen;
- struct patch_info *p;
- struct sample_info *s;
- char buf[128];
-
- skip=0; /* Not necessary, but removes a compiler warning */
-
- s=&M.sample[i];
-
- /* +2 for click-removal */
- p=malloc(sizeof(struct patch_info)+s->length+2);
-
- p->key=GUS_PATCH;
- p->device_no=gus_dev;
- p->instr_no=i;
- p->len=origlen=s->length;
-
- /* PAL = 8287 Hz ; NTSC = 8363 Hz */
- if(s->c2freq == -1)
- p->base_freq=(opt.ntsc_samples ? 8363 : 8287);
- else
- p->base_freq=s->c2freq;
-
- p->base_note=261632; /* C-2 */
- p->high_note=INT_MAX;
- p->low_note=0;
- p->panning=0;
- p->detuning=0;
- p->volume=64; /* Not used in kernel when we have LINEAR volumes */
- p->mode=0; /* Default to signed 8 bit nonlooped samples */
-
- /* Read the first 4 bytes and try to determine if we should skip the first
- * 0, 2 or 4 bytes (amiga modules have a couple of 0-bytes at the start
- * of samples to handle looping; 4 on older modules and 2 on newer ones).
- * We never skip zeroes that are included in loops though (this is a
- * special protection for short samples that often are looped and
- * sound very strange if the looptime is shortened).
- *
- * The above scheme will cause samples to be a few bytes short (and thus
- * played "a bit too early") but they will click less when triggered.
- * If the sample is 16bit it can't be an amiga-sample and nothing is done.
- */
-
- if(!s->bits_16) {
- if(read(fd, p->data, 4) == 4) {
- skip=0;
- if(!p->data[0] && !p->data[1]) {
- skip=2;
- if(!p->data[2] && !p->data[3])
- skip=4;
- }
-
- if(s->looped)
- skip=MIN(skip, s->repeat_start);
-
- lseek(fd, skip-4, SEEK_CUR);
- p->len-=skip;
- s->length=p->len;
- s->repeat_start=MAX(0, s->repeat_start)-skip;
- s->repeat_end=MAX(0, s->repeat_end-skip);
- }
- else {
- free(p);
- return 0; /* Sample too short */
- }
- #if 0
- /* Show the first bytes of the sample */
- if(opt.verbose >= 4) {
- printf("%-22s: ", s->name);
- for(t=0; t < skip; ++t)
- printf("%4d ", (int)p->data[t]);
- }
- #endif
- }
-
- if(s->bits_16)
- p->mode|=WAVE_16_BITS;
-
- if(s->looped) {
- p->loop_start=s->repeat_start;
- p->loop_end=s->repeat_end;
- p->mode|=WAVE_LOOPING;
- }
-
- if(s->unsigned_data)
- p->mode|=WAVE_UNSIGNED;
-
- if(s->looped == LOOP_BIDIR)
- p->mode|=WAVE_BIDIR_LOOP;
-
- /* Some modules seems to be 4 or 8 bytes short. Probably a
- * moduleripper that didn't do it's job too well.
- * Quick'n dirty solution: allow the last sample to be a bit short.
- */
- if((t=read(fd, p->data, p->len)) != p->len) {
- if(p->len-t <= 8 || opt.tolerant) {
- info("(Sample %d was %d bytes short)\n", i, (int)p->len-t);
- p->len=t;
- s->length=t;
- if(s->repeat_end >=t) {
- if(!s->bits_16) {
- s->repeat_end=t-1;
- p->loop_end=t-1;
- }
- else {
- s->repeat_end=t-2;
- p->loop_end=t-2;
- }
- }
- }
- else {
- free(p);
- return 0; /* Sample more than 8 bytes short, abort */
- }
- }
-
- #if 0
- /* Show the rest of the 10 first bytes of the sample */
- if(!s->bits_16 && opt.verbose >= 4) {
- for(t=0; t < 10-skip; ++t)
- printf("%4d ", (int)p->data[t]);
- printf("(%d)\n", skip);
- }
- #endif
-
- #if 0
- /* Modify the sample after loop_end so the GF1 on the GUS interpolates
- * correctly.
- * This really doesn't work work if the last sample is included in the
- * loop (has to be done by the kernel then).
- */
-
- if(s->looped) {
- if(!s->bits_16)
- ((char *)p->data)[p->loop_end+1]=
- ((char *)p->data)[p->loop_start];
- else
- ((short *)p->data)[p->loop_end/2+1]=
- ((short *)p->data)[p->loop_start/2];
- }
- #endif
-
- /* Attempt to minimize clicking/popping on looped samples by
- * connecting samples at the loopingpoint with a straight line.
- * Samples outside the loop will never be modified.
- */
- if(s->looped && opt.click_removal > 0 && origlen > opt.click_removal) {
- span=2+1; /* Change 2 last bytes */
- if(!s->bits_16) {
- if(p->loop_end+1-span < p->loop_start)
- span=p->loop_end-p->loop_start+1;
- base=p->data[p->loop_end+1-span];
- delta=p->data[p->loop_end+1]-base;
- for(t=1; t<span; ++t)
- p->data[p->loop_end+1-span+t]=(char)(base+(delta*t)/span);
- }
- else {
- if(p->loop_end+(1-span)*2 < p->loop_start)
- span=(p->loop_end-p->loop_start)/2+1;
- base=((short *)p->data)[p->loop_end/2+1-span];
- delta=((short *)p->data)[p->loop_end/2+1]-base;
- for(t=1; t<span; ++t)
- ((short *)p->data)[p->loop_end/2+1-span+t]=
- (short)(base+(delta*t)/span);
- }
- }
-
- t=gus_dev;
- ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &t);
- if(p->len <= t)
- SEQ_WRPATCH(p, sizeof(struct patch_info)+p->len);
-
- if(p->len > t) {
- s->valid=0;
- sprintf(buf, "Skipping sample %d", i);
- print_status(buf);
- info("Sample %d doesn't fit in GUS-memory - skipped.\n", i);
- sleep(1);
- }
- else
- s->valid=1;
-
- free(p);
-
- return 1;
- }
-
-
- void print_sample_info_header(void)
- {
- if(!opt.verbose)
- return;
-
- printf(
- "\n # Samplename Size Finetune Loopstart Loopend Volume #\n"
- "--------------------------------------------------------------------------\n");
- }
-
-
- void print_sample_info(int i)
- {
- struct sample_info *s;
-
- if(!opt.verbose)
- return;
-
- s=&M.sample[i];
- if((opt.verbose && s->length) || (opt.verbose >= 2)) {
- printf("%c %2d %-22s %6d%c %2d %5d%c %5d %3d %2d %c\n",
- (s->length ? ' ' : '*'),
- i,
- (M.format == MODFORMAT_ULT ? s->dosname :
- fill_string(s->name, 22)),
- s->length,
- (s->bits_16 ? '*' : ' '),
- s->finetune,
- s->repeat_start,
- (s->looped == LOOP_BIDIR ? 'B' : ' '),
- s->repeat_end,
- s->volume,
- i,
- (s->length ? ' ' : '*'));
- }
- }
-