home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 3
/
AACD03.BIN
/
AACD
/
Sound
/
SoX
/
Source
/
smp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-07-18
|
11KB
|
379 lines
/*
* June 30, 1992
* Copyright 1992 Leigh Smith And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Leigh Smith And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
/*
* Sound Tools SampleVision file format driver.
* Output is always in little-endian (80x86/VAX) order.
*
* Derived from: Sound Tools skeleton handler file.
*
* Add: Loop point verbose info. It's a start, anyway.
*/
#include "st.h"
#include <string.h>
#define NAMELEN 30 /* Size of Samplevision name */
#define COMMENTLEN 60 /* Size of Samplevision comment, not shared */
#define MIDI_UNITY 60 /* MIDI note number to play sample at unity */
/* The header preceeding the sample data */
struct smpheader {
char Id[18]; /* File identifier */
char version[4]; /* File version */
char comments[COMMENTLEN]; /* User comments */
char name[NAMELEN + 1]; /* Sample Name, left justified */
};
#define HEADERSIZE (sizeof(struct smpheader) - 1) /* -1 for name's \0 */
/* Samplevision loop definition structure */
struct loop {
ULONG start; /* Sample count into sample data, not byte count */
ULONG end; /* end point */
char type; /* 0 = loop off, 1 = forward, 2 = forw/back */
short count; /* No of times to loop */
};
/* Samplevision marker definition structure */
struct marker {
char name[10]; /* Ascii Marker name */
ULONG position; /* Sample Number, not byte number */
};
/* The trailer following the sample data */
struct smptrailer {
struct loop loops[8]; /* loops */
struct marker markers[8]; /* markers */
char MIDInote; /* for unity pitch playback */
ULONG rate; /* in hertz */
ULONG SMPTEoffset; /* in subframes - huh? */
ULONG CycleSize; /* sample count in one cycle of the */
/* sampled sound -1 if unknown */
};
/* Private data for SMP file */
typedef struct smpstuff {
ULONG NoOfSamps; /* Sample data count in words */
/* comment memory resides in private data because it's small */
char comment[COMMENTLEN + NAMELEN + 3];
} *smp_t;
char *SVmagic = "SOUND SAMPLE DATA ", *SVvers = "2.1 ";
/*
* Read the SampleVision trailer structure.
* Returns 1 if everything was read ok, 0 if there was an error.
*/
static int readtrailer(ft, trailer)
ft_t ft;
struct smptrailer *trailer;
{
int i;
rshort(ft); /* read reserved word */
for(i = 0; i < 8; i++) { /* read the 8 loops */
trailer->loops[i].start = rlong(ft);
ft->loops[i].start = trailer->loops[i].start;
trailer->loops[i].end = rlong(ft);
ft->loops[i].length =
trailer->loops[i].end - trailer->loops[i].start;
trailer->loops[i].type = getc(ft->fp);
ft->loops[i].type = trailer->loops[8].type;
trailer->loops[i].count = rshort(ft);
ft->loops[8].count = trailer->loops[8].count;
}
for(i = 0; i < 8; i++) { /* read the 8 markers */
if (fread(trailer->markers[i].name, 1, 10, ft->fp) != 10)
return(0);
trailer->markers[i].position = rlong(ft);
}
trailer->MIDInote = getc(ft->fp);
trailer->rate = rlong(ft);
trailer->SMPTEoffset = rlong(ft);
trailer->CycleSize = rlong(ft);
return(1);
}
/*
* set the trailer data - loops and markers, to reasonably benign values
*/
void settrailer(ft, trailer, rate)
ft_t ft;
struct smptrailer *trailer;
unsigned int rate;
{
int i;
for(i = 0; i < 8; i++) { /* copy the 8 loops */
if (ft->loops[i].type != 0) {
trailer->loops[i].start = ft->loops[i].start;
/* to mark it as not set */
trailer->loops[i].end = ft->loops[i].start + ft->loops[i].length;
trailer->loops[i].type = ft->loops[i].type;
trailer->loops[i].count = ft->loops[i].count;
} else {
/* set first loop start as FFFFFFFF */
trailer->loops[i].start = ~0;
/* to mark it as not set */
trailer->loops[i].end = 0;
trailer->loops[i].type = 0;
trailer->loops[i].count = 0;
}
}
for(i = 0; i < 8; i++) { /* write the 8 markers */
strcpy(trailer->markers[i].name, " ");
trailer->markers[i].position = ~0;
}
trailer->MIDInote = MIDI_UNITY; /* Unity play back */
trailer->rate = rate;
trailer->SMPTEoffset = 0;
trailer->CycleSize = -1;
}
/*
* Write the SampleVision trailer structure.
* Returns 1 if everything was written ok, 0 if there was an error.
*/
static int writetrailer(ft, trailer)
ft_t ft;
struct smptrailer *trailer;
{
int i;
wshort(ft, 0); /* write the reserved word */
for(i = 0; i < 8; i++) { /* write the 8 loops */
wlong(ft, trailer->loops[i].start);
wlong(ft, trailer->loops[i].end);
putc(trailer->loops[i].type, ft->fp);
wshort(ft, trailer->loops[i].count);
}
for(i = 0; i < 8; i++) { /* write the 8 markers */
if (fwrite(trailer->markers[i].name, 1, 10, ft->fp) != 10)
return(0);
wlong(ft, trailer->markers[i].position);
}
putc(trailer->MIDInote, ft->fp);
wlong(ft, trailer->rate);
wlong(ft, trailer->SMPTEoffset);
wlong(ft, trailer->CycleSize);
return(1);
}
/*
* Do anything required before you start reading samples.
* Read file header.
* Find out sampling rate,
* size and style of samples,
* mono/stereo/quad.
*/
void smpstartread(ft)
ft_t ft;
{
smp_t smp = (smp_t) ft->priv;
int littlendian = 1;
char *endptr;
int i;
int namelen, commentlen;
LONG samplestart;
struct smpheader header;
struct smptrailer trailer;
endptr = (char *) &littlendian;
/* SMP is in Little Endian format. Swap whats read in on */
/* Big Endian machines. */
if (!*endptr)
{
ft->swap = ft->swap ? 0 : 1;
}
/* If you need to seek around the input file. */
if (! ft->seekable)
fail("SMP input file must be a file, not a pipe");
/* Read SampleVision header */
if (fread((char *) &header, 1, HEADERSIZE, ft->fp) != HEADERSIZE)
fail("unexpected EOF in SMP header");
if (strncmp(header.Id, SVmagic, 17) != 0)
fail("SMP header does not begin with magic word %s\n", SVmagic);
if (strncmp(header.version, SVvers, 4) != 0)
fail("SMP header is not version %s\n", SVvers);
/* Format the sample name and comments to a single comment */
/* string. We decrement the counters till we encounter non */
/* padding space chars, so the *lengths* are low by one */
for (namelen = NAMELEN-1;
namelen >= 0 && header.name[namelen] == ' '; namelen--)
;
for (commentlen = COMMENTLEN-1;
commentlen >= 0 && header.comments[commentlen] == ' '; commentlen--)
;
sprintf(smp->comment, "%.*s: %.*s", namelen+1, header.name,
commentlen+1, header.comments);
ft->comment = smp->comment;
report("SampleVision file name and comments: %s", ft->comment);
/* Extract out the sample size (always intel format) */
smp->NoOfSamps = rlong(ft);
/* mark the start of the sample data */
samplestart = ftell(ft->fp);
/* seek from the current position (the start of sample data) by */
/* NoOfSamps * 2 */
if (fseek(ft->fp, smp->NoOfSamps * 2L, 1) == -1)
fail("SMP unable to seek to trailer");
if (!readtrailer(ft, &trailer))
fail("unexpected EOF in SMP trailer");
/* seek back to the beginning of the data */
if (fseek(ft->fp, samplestart, 0) == -1)
fail("SMP unable to seek back to start of sample data");
ft->info.rate = (int) trailer.rate;
ft->info.size = WORD;
ft->info.style = SIGN2;
ft->info.channels = 1;
if (verbose) {
fprintf(stderr, "SampleVision trailer:\n");
for(i = 0; i < 8; i++) if (1 || trailer.loops[i].count) {
#ifdef __alpha__
fprintf(stderr, "Loop %d: start: %6d", i, trailer.loops[i].start);
fprintf(stderr, " end: %6d", trailer.loops[i].end);
#else
fprintf(stderr, "Loop %d: start: %6ld", i, trailer.loops[i].start);
fprintf(stderr, " end: %6ld", trailer.loops[i].end);
#endif
fprintf(stderr, " count: %6d", trailer.loops[i].count);
fprintf(stderr, " type: ");
switch(trailer.loops[i].type) {
case 0: fprintf(stderr, "off\n"); break;
case 1: fprintf(stderr, "forward\n"); break;
case 2: fprintf(stderr, "forward/backward\n"); break;
}
}
fprintf(stderr, "MIDI Note number: %d\n\n", trailer.MIDInote);
}
ft->instr.nloops = 0;
for(i = 0; i < 8; i++)
if (trailer.loops[i].type)
ft->instr.nloops++;
for(i = 0; i < ft->instr.nloops; i++) {
ft->loops[i].type = trailer.loops[i].type;
ft->loops[i].count = trailer.loops[i].count;
ft->loops[i].start = trailer.loops[i].start;
ft->loops[i].length = trailer.loops[i].end
- trailer.loops[i].start;
}
ft->instr.MIDIlow = ft->instr.MIDIhi =
ft->instr.MIDInote = trailer.MIDInote;
if (ft->instr.nloops > 0)
ft->instr.loopmode = LOOP_8;
else
ft->instr.loopmode = LOOP_NONE;
}
/*
* Read up to len samples from file.
* Convert to signed longs.
* Place in buf[].
* Return number of samples read.
*/
LONG smpread(ft, buf, len)
ft_t ft;
LONG *buf, len;
{
smp_t smp = (smp_t) ft->priv;
LONG datum;
int done = 0;
for(; done < len && smp->NoOfSamps; done++, smp->NoOfSamps--) {
datum = rshort(ft);
/* scale signed up to long's range */
*buf++ = LEFT(datum, 16);
}
return done;
}
/*
* Do anything required when you stop reading samples.
* Don't close input file!
*/
void smpstopread(ft)
ft_t ft;
{
}
void smpstartwrite(ft)
ft_t ft;
{
int littlendian = 1;
char *endptr;
smp_t smp = (smp_t) ft->priv;
struct smpheader header;
endptr = (char *) &littlendian;
/* SMP is in Little Endian format. Swap whats read in on */
/* Big Endian machines. */
if (!*endptr)
{
ft->swap = ft->swap ? 0 : 1;
}
/* If you have to seek around the output file */
if (! ft->seekable)
fail("Output .smp file must be a file, not a pipe");
/* If your format specifies any of the following info. */
ft->info.size = WORD;
ft->info.style = SIGN2;
ft->info.channels = 1;
strcpy(header.Id, SVmagic);
strcpy(header.version, SVvers);
sprintf(header.comments, "%-*s", COMMENTLEN, "Converted using Sox.");
sprintf(header.name, "%-*.*s", NAMELEN, NAMELEN, ft->comment);
/* Write file header */
if(fwrite(&header, 1, HEADERSIZE, ft->fp) != HEADERSIZE)
fail("SMP: Can't write header completely");
wlong(ft, 0); /* write as zero length for now, update later */
smp->NoOfSamps = 0;
}
void smpwrite(ft, buf, len)
ft_t ft;
LONG *buf, len;
{
smp_t smp = (smp_t) ft->priv;
register int datum;
while(len--) {
datum = (int) RIGHT(*buf++, 16);
wshort(ft, datum);
smp->NoOfSamps++;
}
/* If you cannot write out all of the supplied samples, */
/* fail("SMP: Can't write all samples to %s", ft->filename); */
}
void smpstopwrite(ft)
ft_t ft;
{
smp_t smp = (smp_t) ft->priv;
struct smptrailer trailer;
/* Assign the trailer data */
settrailer(ft, &trailer, ft->info.rate);
writetrailer(ft, &trailer);
if (fseek(ft->fp, 112, 0) == -1)
fail("SMP unable to seek back to save size");
wlong(ft, smp->NoOfSamps);
}