home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Best Objectech Shareware Selections
/
UNTITLED.iso
/
boss
/
musi
/
misc
/
013
/
midimod.c
< prev
next >
Wrap
Text File
|
1993-04-13
|
36KB
|
1,385 lines
/*
* MIDIMOD.C - Amiga Module to MIDI file converter
* Turbo C 2.0
*
* Description: Takes a .mod file and has a good go at converting it to
* a .mid file. Equivalents to certain .mod samples can be
* set to default to particular MIDI instruments. Multiple
* MIDI instrument tables should be supported. Note that .mod
* and .mid are at the end of the file.
*
* Author: Andrew Scott (Adrenalin Software)
*
* Date: 14/3/1993 ver 0.1
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <dos.h>
#include "textwin.h" /* Simple text-windowing environment */
#include "midimod.h" /* Dialog/Info box messages and definitions */
#define ANOTE(x) ((x < 0) ? (-x) : (NoteValue(x)))
#define ENOTE(x,y) ((sam->m > 127) ? (sam->m - 128) : (ANOTE(x) + sam->t[y]))
bfile MidFile, ModFile;
char SongName[21];
samps Samples;
unsigned long PosLog[64];
int PosI = 0;
string MidFN, ModFN;
void OutByte(bfile f, char b)
/* Post: The byte b has been written to the buffer of the file f */
{
if (f->o == BUFFSIZE) {
fwrite(f->b, 1, BUFFSIZE, f->f);
f->o = 0;
}
f->b[f->o++] = b;
}
void FlushOut(bfile f)
/* Pre: f was opened for writing */
/* Post: The file f has has its buffer flushed */
{
if (f->o > 0)
fwrite(f->b, 1, f->o, f->f);
f->o = 0;
}
void CloseOut(bfile f)
/* Pre: f was opened for writing */
/* Post: The file f has been flushed and is now closed */
{
FlushOut(f);
fclose(f->f);
f->f = NULL;
}
int OpenOut(bfile f, string fn)
/* Returns: NZ if the file f has been opened for writing with the name fn */
{
if (f->f != NULL)
CloseOut(f);
f->f = fopen(fn, "wb");
f->o = 0;
return f->f != NULL;
}
unsigned long Beatle(bfile f)
/* Returns: bfile-tell (btell=beatle). The offset from the start */
{
return ftell(f->f) + f->o;
}
unsigned char InByte(bfile f)
/* Pre: f was opened for reading */
/* Returns: The next byte from the file f */
{
if (f->o == BUFFSIZE && !feof(f->f)) {
f->r = fread(f->b, 1, BUFFSIZE, f->f);
if (f->r < BUFFSIZE)
f->b[f->r] = 0;
f->o = 0;
}
if (f->o < f->r)
return f->b[f->o++];
return f->b[f->o];
}
void CloseIn(bfile f)
/* Post: The file f is now closed */
{
fclose(f->f);
f->f = NULL;
}
int OpenIn(bfile f, string fn)
/* Returns: NZ if the file f has been opened for reading with the name fn */
{
if (f->f != NULL)
CloseIn(f);
f->f = fopen(fn, "rb");
f->o = f->r = BUFFSIZE;
return f->f != NULL;
}
void Inskipp(bfile f, unsigned long n) /* Stainless-steel rat for Pres */
/* Pre: f was opened for reading */
/* Post: f's file pointer has skipped forward n bytes */
{
n += f->o;
while (n >= BUFFSIZE && !feof(f->f)) {
f->r = fread(f->b, 1, BUFFSIZE, f->f);
if (f->r < BUFFSIZE)
f->b[f->r] = 0;
n -= BUFFSIZE;
}
f->o = n; /* hmmm.. may cause an error if was eof.. X-fingers */
}
struct bpos FPos(bfile f)
/* Returns: All necessary information regarding file f's status */
{
struct bpos x;
x.d = *f;
x.p = ftell(f->f);
return x;
}
void FGoto(bfile f, struct bpos x)
/* Pre: x was the status of f previously */
/* Post: File f has had its status changed to x */
{
fseek(f->f, x.p, SEEK_SET);
*f = x.d;
}
int WriteVLQ(bfile f, unsigned long i)
/*
* Returns: # of bytes written after a variable-length-quantity equivalent
* of i has been written to the file f.
*/
{
int x = 0;
unsigned long buffer;
buffer = i & 127;
while ((i >>= 7) > 0)
buffer = ((buffer << 8) | 128) + (i & 127);
while (1) {
OutByte(f, buffer & 255);
x++;
if (buffer & 128)
buffer >>= 8;
else
return x;
}
}
string InitFile(bfile f, string deffn, string t, int inpm)
/* Returns: NULL if file is unacceptable, the filename otherwise. The
* filename corresponds to file f, type t, with default filename deffn.
* Will open an input file if inpm is NZ. deffn will be freed.
*/
{
int r = 0;
string newfn;
_IF[1] = t;
newfn = DialogBox(_IF, deffn);
free(deffn);
if (! *newfn) {
free(newfn);
return NULL;
}
if (inpm)
r = OpenIn(f, newfn);
else if (fclose(fopen(newfn, "r"))==EOF || tolower(InfoBox(_OUTE))=='y')
r = OpenOut(f, newfn);
if (!r) {
free(newfn);
return NULL;
}
return newfn;
}
int MKTest(bfile f)
/* Returns: The number of samples in the Module file f */
{
unsigned long offset;
int i = 15;
char s[4];
offset = ftell(f->f);
if (!fseek(f->f, 1080, SEEK_SET)) {
fread(s, 1, 4, f->f);
if (!memcmp(s, "M.K.", 4) || !memcmp(s, "FLT",3))
i = 31;
}
fseek(f->f, offset, SEEK_SET);
return i;
}
string SimplifyName(string s)
/*
* Returns: A string similar to s, but has had any nasty headers removed
* any leading spaces or trailing spaces, and all made lower-case
*/
{
string t, r, x;
x = strchr(s, ':');
if (x != NULL && x-s == 5 && tolower(s[0])=='s' && tolower(s[1])=='t' &&
s[2]=='-') {
r = x = (string) malloc(18);
t = s + 6;
while (*(x++) = *(t++)); /* remove soundtracker header */
} else
r = strdup(s);
for (t = r; *t == ' '; t++);
x = r;
while (*(x++) = *(t++)); /* remove leading spaces */
t = strchr(r, ' ');
if (t != NULL)
*t = 0; /* remove 'trailing' spaces */
return strlwr((string) realloc(r, strlen(r) + 1));
}
string GetLine(FILE *f)
/* Returns: Next line from file f, NULL on error/eof */
{
string s, t;
int c;
if ((t = s = (string) malloc(MAXSTRING))==NULL) {
InfoBox(_OOME);
return NULL;
}
while ((c = fgetc(f)) != EOF && c != '\n')
*(t++) = c;
if (s == t) {
free(s);
return NULL;
}
*t = 0;
return (string) realloc(s, t-s+1);
}
int ReadModSpecs(bfile f, string n, samps s)
/*
* Returns: Z if f is not a supported Amiga Module, else n is set to
* be the name of the Module and s is set to hold sample information
*/
{
unsigned char b, c;
int i;
string t1;
samp *t2;
for (i = 20, t1 = n; i--; *(t1++) = InByte(f));
*t1 = 0;
c = s->n = MKTest(f);
for (t2 = s->s; c--; t2++) {
for (i = 22, t1 = t2->n; i--; *(t1++) = InByte(f));
*t1 = 0;
b = InByte(f);
t2->l = 256 * b + InByte(f);
if (t2->l < 4)
t2->l = 0; /* 6 bytes is pretty much a non-sample */
b = InByte(f);
t2->v = InByte(f);
InByte(f);
InByte(f);
b = InByte(f);
if (256 * b + InByte(f) > 1 && t2->l)
t2->l = -1; /* looping: plays 'forever' */
t2->m = 0;
t2->t[0] = 0; /* set transposition values to 0 */
t2->t[1] = 0;
t2->t[2] = 0;
}
return !feof(f->f);
}
int SetDefaults(samps s, string fn)
/*
* Returns: NZ if the samples in s have been sucessfully allocated default
* values corresponding to definitions in the DEF_MAPFILE file, and from
* a .mm file corresponding to the filename fn
*/
{
FILE *f;
char i, m[MAXSTRING];
int d, e[3], v;
samp *sam;
string n, t;
bfile mmf;
t = strchr(strcpy(m, fn), '.');
if (t==NULL) {
i = strlen(m);
m[i] = '.';
} else
i = t-m;
m[++i] = 'm';
m[++i] = 'm';
m[++i] = 0;
if (OpenIn(mmf, m)) {
for (i = s->n, sam = s->s; i--; sam++) {
sam->m = InByte(mmf);
sam->t[0] = (signed char) InByte(mmf);
sam->t[1] = (signed char) InByte(mmf);
sam->t[2] = (signed char) InByte(mmf);
InByte(mmf); /* volume data - not used */
InByte(mmf);
InByte(mmf);
}
CloseIn(mmf);
}
if ((f = fopen(DEF_MAPFILE, "rt"))==NULL) {
_NOFIL[3] = DEF_MAPFILE;
InfoBox(_NOFIL);
return 0;
}
i = s->n;
for (sam = s->s; i--; sam++)
if (sam->l) {
n = SimplifyName(sam->n);
t = GetLine(f);
sscanf(t, "%s %d %d %d %d", m, &d, &e[0], &e[1], &e[2]);
if ((v = strcmp(m, n))>0) {
rewind(f);
free(t);
t = GetLine(f);
sscanf(t, "%s %d %d %d %d", m, &d, &e[0], &e[1], &e[2]);
v = strcmp(m, n);
}
free(t);
while (v < 0 && (t = GetLine(f)) != NULL) {
sscanf(t, "%s %d %d %d %d", m, &d, &e[0], &e[1], &e[2]);
free(t);
v = strcmp(m, n);
}
if (!v) {
sam->m = d;
sam->t[0] = e[0];
sam->t[1] = e[1];