greed/CODE/IMPORT.C

1829 lines
57 KiB
C
Raw Permalink Normal View History

2014-12-12 00:00:00 +00:00
/****************************************************************************
*
* Digital Sound Interface Kit (DSIK)
* Version 2.00
*
* by Carlos Hasan
*
* Filename: import.c
* Version: Revision 1.5
*
* Language: WATCOM C
* Environment: IBM PC (DOS/4GW)
*
* Description: Import routines for module and sample files.
*
* Revision History:
* ----------------
*
* Revision 1.5 94/12/31 10:47:44 chv
* Minor changes.
*
* Revision 1.4 94/12/26 11:37:34 chv
* Fixed bug in the MTM pattern loader (notes were transposed one halfnote).
*
* Revision 1.3 94/11/17 16:58:20 chv
* Added Composer 669 and Scream Tracker 2.0 import routines
*
* Revision 1.2 94/11/08 15:10:42 chv
* Added Amiga IFF/8SVX sample file import routines
*
* Revision 1.1 94/10/26 13:12:43 chv
* Added Multitracker MTM modules import routines
*
* Revision 1.0 94/10/03 12:50:22 chv
* Initial revision
*
****************************************************************************/
#include <io.h>
#include <fcntl.h>
#include <malloc.h>
#include <string.h>
#include <sys\stat.h>
#include "d_global.h"
#include "audio.h"
#include "import.h"
/******************* SOUND/SAMPLE FILES IMPORT ROUTINES ********************/
/*----------------- RAW Sample Files Import Routines ----------------------*/
/****************************************************************************
*
* Function: LoadSample
* Parameters: Handle - DOS file handle
* Length - sample length
* Flags - sample format
*
* Returns: Sample address or NULL when an error has occurred
* while loading the file.
*
* Description: Load 8-bit signed/unsigned mono samples from disk.
*
****************************************************************************/
static Sample *LoadSample(int Handle, long Length, int Flags)
{
Sample *SampPtr;
void *DataPtr;
if (!(SampPtr = (Sample*)calloc(1,sizeof(Sample)))) {
dError = ERR_NOMEM;
return NULL;
}
SampPtr->Flags = Flags;
SampPtr->Volume = 64;
SampPtr->Length = SampPtr->LoopStart = SampPtr->LoopEnd = Length;
SampPtr->DataPtr = NULL;
SampPtr->Rate = MIDCFREQ;
if (!SampPtr->Length) {
return SampPtr;
}
if (!(SampPtr->DataPtr = DataPtr = malloc(Length))) {
dError = ERR_NOMEM;
free(SampPtr);
return NULL;
}
if (read(Handle,DataPtr,Length) != Length) {
dError = ERR_FILEIO;
free(DataPtr);
free(SampPtr);
return NULL;
}
if (!dMemAlloc(SampPtr)) {
dError = ERR_NODRAM;
free(DataPtr);
free(SampPtr);
return NULL;
}
if (dGetDriverFlags() & AF_DRAM) {
free(DataPtr);
}
return SampPtr;
}
/*---------------- Creative Labs' Voice Import Routines -------------------*/
/****************************************************************************
*
* Function: VOCLoadSample
* Parameters: Handle - DOS file handle
* Length - file length
*
* Returns: Sample address or NULL when an error has occurred
* while loading the file.
*
* Description: Load Creative Labs' Voice 8-bit mono samples from disk.
*
****************************************************************************/
static Sample *VOCLoadSample(int Handle, long Length)
{
Sample *SampPtr;
VocHeader VocHdr;
VocBlock VocBlk;
VocData VocDta;
VocExtInfo VocExt;
long Size;
/* read VOC header */
if (read(Handle,&VocHdr,sizeof(VocHdr)) != sizeof(VocHdr)) {
dError = ERR_FILEIO;
return NULL;
}
if (memcmp(VocHdr.Magic,VOC_HDR,sizeof(VocHdr.Magic))) {
dError = ERR_FORMAT;
return NULL;
}
/* seek VOC data block */
if (lseek(Handle,VocHdr.BlockPos-sizeof(VocHdr),SEEK_CUR) < 0) {
dError = ERR_FILEIO;
return NULL;
}
do {
if (read(Handle,&VocBlk,sizeof(VocBlk)) != sizeof(VocBlk)) {
dError = ERR_FILEIO;
return NULL;
}
Size = *((long*)VocBlk.Size) & 0xFFFFFF;
if (VocBlk.Type == VOC_DATA) {
if (read(Handle,&VocDta,sizeof(VocDta)) != sizeof(VocDta)) {
dError = ERR_FILEIO;
return NULL;
}
if (VocDta.Format != VOC_FMT_8BITS) {
dError = ERR_FORMAT;
return NULL;
}
Size -= sizeof(VocDta);
}
else if (VocBlk.Type == VOC_EXTINFO) {
if (read(Handle,&VocExt,sizeof(VocExt)) != sizeof(VocExt)) {
dError = ERR_FILEIO;
return NULL;
}
if (VocExt.Mode != VOC_MODE_MONO) {
dError = ERR_FORMAT;
return NULL;
}
}
else {
if (lseek(Handle,Size,SEEK_CUR) < 0) {
dError = ERR_FILEIO;
return NULL;
}
}
} while (VocBlk.Type != VOC_DATA);
/* load VOC PCM samples */
if (!(SampPtr = LoadSample(Handle,Size,SF_8BITS|SF_UNSIGNED)))
return NULL;
SampPtr->Volume = 64;
SampPtr->Rate = (word)(1000000L/(256-VocDta.TimeConst));
return SampPtr;
}
/*------------- Amiga IFF/8SVX sample format Import Routines --------------*/
/****************************************************************************
*
* Function: IFFLoadSample
* Parameters: Handle - DOS file handle
* Length - file length
*
* Returns: Sample address or NULL when an error has occurred
* while loading the file.
*
* Description: Load 8-bit mono signed IFF sample files.
*
****************************************************************************/
static Sample *IFFLoadSample(int Handle, long Length)
{
Sample *SampPtr;
IffHeader Header;
IffBlock Block;
IffVHdr VHdr;
IffChan Chan;
/* read IFF/8SVX header */
if (read(Handle,&Header,sizeof(Header)) != sizeof(Header)) {
dError = ERR_FILEIO;
return NULL;
}
if (Header.ID != IFF_FORM || Header.Type != IFF_8SVX) {
dError = ERR_FORMAT;
return NULL;
}
/* seek IFF/8SVX BODY chunk */
SampPtr = NULL;
VHdr.Rate = MIDCFREQ;
Header.Length = LSWAP(Header.Length);
if (Header.Length & 1) Header.Length++;
Header.Length -= sizeof(Header.Type);
while (Header.Length) {
if (read(Handle,&Block,sizeof(Block)) != sizeof(Block)) {
dError = ERR_FILEIO;
return NULL;
}
Block.Length = LSWAP(Block.Length);
if (Block.Length & 1) Block.Length++;
Header.Length -= sizeof(Block) + Block.Length;
if (Block.ID == IFF_VHDR) {
if (Block.Length != sizeof(VHdr)) {
dError = ERR_FORMAT;
return NULL;
}
if (read(Handle,&VHdr,sizeof(VHdr)) != sizeof(VHdr)) {
dError = ERR_FILEIO;
return NULL;
}
VHdr.Rate = WSWAP(VHdr.Rate);
if (VHdr.Format != 0) {
dError = ERR_FORMAT;
return NULL;
}
}
else if (Block.ID == IFF_CHAN) {
if (Block.Length != sizeof(Chan)) {
dError = ERR_FORMAT;
return NULL;
}
if (read(Handle,&Chan,sizeof(Chan)) != sizeof(Chan)) {
dError = ERR_FILEIO;
return NULL;
}
Chan.Channels = LSWAP(Chan.Channels);
Chan.Channels = (Chan.Channels & 0x01) +
((Chan.Channels & 0x02) >> 1) +
((Chan.Channels & 0x04) >> 2) +
((Chan.Channels & 0x08) >> 3);
if (Chan.Channels != 1) {
dError = ERR_FORMAT;
return NULL;
}
}
else if (Block.ID == IFF_BODY) {
if (!(SampPtr = LoadSample(Handle,Block.Length,SF_8BITS|SF_SIGNED)))
return NULL;
SampPtr->Volume = 64;
SampPtr->Rate = VHdr.Rate;
break;
}
else if (lseek(Handle,Block.Length,SEEK_CUR) < 0) {
dError = ERR_FILEIO;
return NULL;
}
}
if (!SampPtr) dError = ERR_FORMAT;
return SampPtr;
}
/*------------ Amiga 8-bit RAW Sample Files Import Routines ---------------*/
/****************************************************************************
*
* Function: RAWLoadSample
* Parameters: Handle - DOS file handle
* Length - sample length
*
* Returns: Sample address or NULL when an error has occurred
* while loading the file.
*
* Description: Load 8-bit signed/unsigned mono samples from disk.
*
****************************************************************************/
static Sample *RAWLoadSample(int Handle, long Length)
{
return LoadSample(Handle,Length,SF_8BITS|SF_SIGNED);
}
/******************* MUSIC MODULE FILES IMPORT ROUTINES ********************/
/*--------------- Protracker/Fastracker Import Routines -------------------*/
static word PeriodTable[96] = {
6848,6464,6096,5760,5424,5120,4832,4560,4304,4064,3840,3624,
3424,3232,3048,2880,2712,2560,2416,2280,2152,2032,1920,1812,
1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906,
856,808,762,720,678,640,604,570,538,508,480,453,
428,404,381,360,339,320,302,285,269,254,240,226,
214,202,190,180,170,160,151,143,135,127,120,113,
107,101,95,90,85,80,75,71,67,63,60,56,
53,50,47,45,42,40,37,35,33,31,30,28 };
static word RateTable[16] = {
8363,8424,8485,8546,8608,8670,8733,8797,
7894,7951,8008,8066,8125,8184,8243,8303 };
/****************************************************************************
*
* Function: MODLoadPattern
* Parameters: Handle - file handle
* NumTracks - number of tracks
*
* Returns: Pattern structure or NULL if error.
*
* Description: Used to load MOD patterns.
*
****************************************************************************/
static Pattern *MODLoadPattern(int Handle, int NumTracks)
{
Pattern *DPatt;
byte *SPatt;
byte *S,*D;
byte Row,Track,Flags,Note,Inst,Effect,Param;
word Period;
if (!(DPatt = (Pattern*)malloc(2+(1+5*NumTracks)*64))) {
dError = ERR_NOMEM;
return NULL;
}
if (!(SPatt = (byte*)malloc(NumTracks<<8))) {
dError = ERR_NOMEM;
free(DPatt);
return NULL;
}
if (read(Handle,SPatt,NumTracks<<8) != (NumTracks<<8)) {
dError = ERR_FILEIO;
free(SPatt);
free(DPatt);
return NULL;
}
S = SPatt;
D = DPatt->Data;
for (Row = 0; Row < 64; Row++) {
for (Track = 0; Track < NumTracks; Track++) {
Period = (((word)S[0] & 0x0F) << 8) | ((word)S[1]);
Inst = (S[0] & 0xF0) | ((S[2] & 0xF0)>>4);
Effect = S[2] & 0x0F;
Param = S[3];
S += 4;
for (Note = 0; Note < 96; Note++)
if (Period >= PeriodTable[Note]) break;
if (Note >= 96) Note = 0; else Note++;
Flags = 0;
if (Note) Flags |= 0x80;
if (Inst) Flags |= 0x40;
if (Effect | Param) Flags |= 0x10;
if (Flags) {
*D++ = Flags | (Track & 0x0F);
if (Note) *D++ = Note;
if (Inst) *D++ = Inst;
if (Effect | Param) {
*D++ = Effect;
*D++ = Param;
}
}
}
*D++ = 0;
}
free(SPatt);
DPatt->Length = D-(byte*)DPatt;
return (Pattern*)realloc(DPatt,DPatt->Length);
}
/****************************************************************************
*
* Function: MODLoadSample
* Parameters: Handle - file handle
* Instr - MOD sample structure
*
* Returns: Sample structure or NULL if error.
*
* Description: Used to load MOD samples.
*
****************************************************************************/
static Sample *MODLoadSample(int Handle, MODSample *Instr)
{
Sample *SampPtr;
Instr->Length = WSWAP(Instr->Length) << 1;
Instr->LoopStart = WSWAP(Instr->LoopStart) << 1;
Instr->LoopLength = WSWAP(Instr->LoopLength) << 1;
if (!(SampPtr = LoadSample(Handle,Instr->Length,SF_8BITS|SF_SIGNED)))
return NULL;
strncpy(SampPtr->SampleName,Instr->SampleName,sizeof(Instr->SampleName));
SampPtr->Volume = Instr->Volume;
SampPtr->Rate = RateTable[Instr->Finetune & 0x0F];
if (Instr->LoopLength > 2) {
SampPtr->Flags |= SF_LOOPED;
SampPtr->LoopStart = SampPtr->LoopEnd = Instr->LoopStart;
SampPtr->LoopEnd += Instr->LoopLength;
if (SampPtr->LoopEnd >= SampPtr->Length)
SampPtr->LoopEnd = SampPtr->Length;
if (SampPtr->LoopStart >= SampPtr->LoopEnd)
SampPtr->LoopStart = SampPtr->LoopEnd;
}
return SampPtr;
}
/****************************************************************************
*
* Function: MODLoadModule
* Parameters: Handle - DOS file handle
* Length - file length
*
* Returns: Music module address or NULL when an error has occurred
* while loading the file.
*
* Description: Load Protracker/Fastracker (MOD) music modules from disk.
*
****************************************************************************/
static DSM *MODLoadModule(int Handle, long Length)
{
DSM *Module;
MODSong Header;
int Index;
if (!(Module = (DSM*)calloc(1,sizeof(DSM)))) {
dError = ERR_NOMEM;
return NULL;
}
if (read(Handle,&Header,sizeof(Header)) != sizeof(Header)) {
dError = ERR_FILEIO;
dFreeModule(Module);
return NULL;
}
if (Header.Magic == MOD_MK || Header.Magic == MOD_FLT4) {
Module->Header.NumTracks = 4;
}
else if (Header.Magic == MOD_6CHN) {
Module->Header.NumTracks = 6;
}
else if (Header.Magic == MOD_8CHN || Header.Magic == MOD_FLT8) {
Module->Header.NumTracks = 8;
}
else {
dError = ERR_FORMAT;
dFreeModule(Module);
return NULL;
}
/* fill the SONG structure */
strncpy(Module->Header.ModuleName,Header.SongName,sizeof(Header.SongName));
Module->Header.OrderPos = 0;
Module->Header.ReStart = Header.ReStart;
Module->Header.NumOrders = Header.NumOrders;
Module->Header.NumSamples = 31;
Module->Header.NumPatterns = 0;
Module->Header.GlobalVolume = 64;
Module->Header.MasterVolume = 768/Module->Header.NumTracks;
Module->Header.InitTempo = 6;
Module->Header.InitBPM = 125;
for (Index = 0; Index < 128; Index++) {
Module->Header.Orders[Index] = Header.Orders[Index];
if (Module->Header.NumPatterns < Header.Orders[Index])
Module->Header.NumPatterns = Header.Orders[Index];
}
(Module->Header.NumPatterns)++;
for (Index = 0; Index < Module->Header.NumTracks; Index++) {
Module->Header.ChanMap[Index] = ((Index & 3) == 0 ||
(Index & 3) == 3) ? PAN_LEFT : PAN_RIGHT;
}
/* allocate sample and pattern pointer tables */
if (!(Module->Samples = (Sample**)calloc(Module->Header.NumSamples,sizeof(Sample *)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
if (!(Module->Patterns = (Pattern**)calloc(Module->Header.NumPatterns,sizeof(Pattern *)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
/* fill the PATT structures */
for (Index = 0; Index < Module->Header.NumPatterns; Index++) {
if (!(Module->Patterns[Index] =
MODLoadPattern(Handle,Module->Header.NumTracks))) {
dFreeModule(Module);
return NULL;
}
}
/* fill the INST structures */
for (Index = 0; Index < Module->Header.NumSamples; Index++) {
if (!(Module->Samples[Index] =
MODLoadSample(Handle,&Header.Samples[Index]))) {
dFreeModule(Module);
return NULL;
}
}
return Module;
}
/*----------------- Scream Tracker 3.0 Import Routines --------------------*/
/****************************************************************************
*
* Function: S3MLoadPattern
* Parameters: Handle - file handle
* SeekPos - pattern relative file position
* ChanMap - 32 channels remap table
*
* Returns: Pattern structure or NULL if error.
*
* Description: Used to load S3M patterns.
*
****************************************************************************/
static Pattern *S3MLoadPattern(int Handle, long SeekPos, byte *ChanMap)
{
Pattern *DPatt;
byte *SPatt;
byte TrackParam[MAXTRACKS];
byte *S,*D,*MaxD;
word Length;
byte Row,Flags,Track,Note,Inst,Volume,Effect,Param,PattLoop;
if (!(DPatt = (Pattern*)malloc(70+2+(1+6*MAXTRACKS)*64))) {
dError = ERR_NOMEM;
return NULL;
}
if (lseek(Handle,SeekPos,SEEK_SET) < 0) {
dError = ERR_FILEIO;
free(DPatt);
return NULL;
}
if (read(Handle,&Length,sizeof(Length)) != sizeof(Length)) {
dError = ERR_FILEIO;
free(DPatt);
return NULL;
}
if (!(SPatt = (byte*)malloc(Length -= 2))) {
dError = ERR_NOMEM;
free(DPatt);
return NULL;
}
if (read(Handle,SPatt,Length) != Length) {
dError = ERR_FILEIO;
free(SPatt);
free(DPatt);
return NULL;
}
for (Track = PattLoop = 0; Track < MAXTRACKS; Track++) {
TrackParam[Track] = 0;
}
S = SPatt;
D = DPatt->Data;
MaxD = D+2+(1+6*MAXTRACKS)*64;
for (Row = 0; Row < 64; Row++) {
while (D < MaxD) {
if (!(Flags = *S++)) break;
Note = 255;
Inst = 0;
Volume = 255;
Effect = 0;
Param = 0;
Track = ChanMap[Flags & 0x1F];
if (Flags & 0x20) {
Note = *S++;
Inst = *S++;
}
if (Flags & 0x40) {
Volume = *S++;
}
if (Flags & 0x80) {
Effect = *S++;
Param = *S++;
}
if (Track >= MAXTRACKS) continue;
if (Note == 0xFE) {
Note = Volume = 0;
}
else if (Note == 0xFF) {
Note = 0;
}
else {
Note = (Note & 0x0F) + 12*(Note >> 4);
if (Note >= 96) Note = 95; else Note++;
}
if (Param) TrackParam[Track] = Param;
Effect += 64;
if ((Param == 0) && (((Effect >= 'D') && (Effect <= 'G')) ||
(Effect == 'K') || (Effect == 'L') || (Effect == 'Q'))) {
Param = TrackParam[Track];
}
switch (Effect) {
case 'A':
if (Param <= 0x1F) Effect = 0x0F;
else Effect = Param = 0;
break;
case 'B':
Effect = 0x0B;
break;
case 'C':
Effect = 0x0D;
break;
case 'D':
if ((Param & 0xF0) == 0x00) {
Effect = 0x0A;
Param &= 0x0F;
}
else if ((Param & 0x0F) == 0x00) {
Effect = 0x0A;
Param &= 0xF0;
}
else if ((Param & 0xF0) == 0xF0) {
Effect = 0x0E;
Param = 0xB0 | (Param & 0x0F);
}
else if ((Param & 0x0F) == 0x0F) {
Effect = 0x0E;
Param = 0xA0 | (Param >> 4);
}
else Effect = Param = 0;
break;
case 'E':
if ((Param & 0xF0) == 0xF0) {
Effect = 0x0E;
Param = 0x20 | (Param & 0x0F);
}
else if ((Param & 0xF0) == 0xE0) {
Effect = 0x0E;
Param = 0x20 | ((Param & 0x0F) >> 2);
}
else {
Effect = 0x02;
}
break;
case 'F':
if ((Param & 0xF0) == 0xF0) {
Effect = 0x0E;
Param = 0x10 | (Param & 0x0F);
}
else if ((Param & 0xF0) == 0xE0) {
Effect = 0x0E;
Param = 0x10 | ((Param & 0x0F) >> 2);
}
else {
Effect = 0x01;
}
break;
case 'G':
Effect = 0x03;
break;
case 'H':
Effect = 0x04;
break;
case 'I':
Effect = 0x0E;
Param = 0x90 | (Param & 0x0F); /* emu tremor with retrig */
break;
case 'J':
Effect = 0x00;
break;
case 'K':
Effect = 0x06;
break;
case 'L':
Effect = 0x05;
break;
case 'O':
Effect = 0x09;
break;
case 'Q':
Effect = 0x0A; /* emu retrigvol with volslide */
if ((Param >> 4) >= 8)
Param = (((Param >> 4)/(Param & 0x0F))+1) << 4;
else
Param = (((Param >> 4)/(Param & 0x0F))+1);
break;
case 'R':
Effect = 0x07;
break;
case 'S':
switch (Param & 0xF0) {
case 0x00:
Effect = 0x0E;
Param = 0x00 | (Param & 0x0F);
break;
case 0x10:
Effect = 0x0E;
Param = 0x30 | (Param & 0x0F);
break;
case 0x20:
Effect = 0x0E;
Param = 0x50 | (Param & 0x0F);
break;
case 0x30:
Effect = 0x0E;
Param = 0x70 | (Param & 0x0F);
break;
case 0x40:
Effect = 0x0E;
Param = 0x40 | (Param & 0x0F);
break;
case 0x80:
Effect = 0x0E;
Param = 0x80 | (Param & 0x0F);
break;
case 0xA0:
Effect = 0x08;
switch (Param & 0x0F) {
case 0x00:
case 0x02:
Param = PAN_LEFT;
break;
case 0x01:
case 0x03:
Param = PAN_RIGHT;
break;
case 0x04:
Param = (PAN_LEFT + PAN_MIDDLE)/2;
break;
case 0x05:
Param = (PAN_MIDDLE + PAN_RIGHT)/2;
break;
case 0x06:
case 0x07:
Param = PAN_MIDDLE;
break;
default:
Effect = Param = 0;
break;
}
break;
case 0xB0:
if ((Param & 0x0F) == 0x00)
Param = PattLoop;
else {
PattLoop = Param & 0x0F;
Param = 0xB0;
}
Effect = 0x0E;
Param = 0x60 | (Param & 0x0F);
break;
case 0xC0:
Effect = 0x0E;
Param = 0xC0 | (Param & 0x0F);
break;
case 0xD0:
Effect = 0x0E;
Param = 0xD0 | (Param & 0x0F);
break;
case 0xE0:
Effect = 0x0E;
Param = 0xE0 | (Param & 0x0F);
break;
default:
Effect = Param = 0;
break;
}
break;
case 'T':
if (Param >= 0x20) Effect = 0x0F;
else Effect = Param = 0;
break;
case 'X':
Effect = 0x08;
break;
case 'Z':
Effect = 0x0B;
Param = 0x80 | Param;
break;
default:
Effect = Param = 0;
break;
}
Flags = 0;
if (Note) Flags |= 0x80;
if (Inst) Flags |= 0x40;
if (Volume <= 64) Flags |= 0x20;
if (Effect | Param) Flags |= 0x10;
if (Flags) {
*D++ = (Flags | (Track & 0x0F));
if (Note) *D++ = Note;
if (Inst) *D++ = Inst;
if (Volume <= 64) *D++ = Volume;
if (Effect | Param) {
*D++ = Effect;
*D++ = Param;
}
}
}
*D++ = 0x00;
}
free(SPatt);
DPatt->Length = D-(byte*)DPatt;
return (Pattern*)realloc(DPatt,DPatt->Length);
}
/****************************************************************************
*
* Function: S3MLoadSample
* Parameters: Handle - file handle
* SeekPos - sample relative file position
*
* Returns: Sample structure or NULL if error.
*
* Description: Used to load S3M samples.
*
****************************************************************************/
static Sample *S3MLoadSample(int Handle, long SeekPos)
{
S3MSample Instr;
Sample *SampPtr;
if (lseek(Handle,SeekPos,SEEK_SET) < 0) {
dError = ERR_FILEIO;
return NULL;
}
if (read(Handle,&Instr,sizeof(Instr)) != sizeof(Instr)) {
dError = ERR_FILEIO;
return NULL;
}
if (Instr.Type == 1 && Instr.Magic != S3M_SCRS) {
dError = ERR_FORMAT;
return NULL;
}
if (Instr.Type != 1) {
Instr.Type = Instr.Volume = Instr.Flags = Instr.Rate = 0;
Instr.DataPtr = Instr.Length = Instr.LoopStart = Instr.LoopEnd = 0;
}
else if (lseek(Handle,(dword)Instr.DataPtr<<4,SEEK_SET) < 0) {
dError = ERR_FILEIO;
return NULL;
}
if (!(SampPtr = LoadSample(Handle,Instr.Length,SF_8BITS|SF_UNSIGNED)))
return NULL;
strcpy(SampPtr->SampleName,Instr.SampleName);
strcpy(SampPtr->FileName,Instr.FileName);
SampPtr->Volume = Instr.Volume;
SampPtr->Rate = Instr.Rate;
if (Instr.Flags) {
SampPtr->Flags |= SF_LOOPED;
SampPtr->LoopStart = Instr.LoopStart;
SampPtr->LoopEnd = Instr.LoopEnd;
}
return SampPtr;
}
/****************************************************************************
*
* Function: S3MLoadModule
* Parameters: Handle - DOS file handle
* Length - file length
*
* Returns: Music module address or NULL when an error has occurred
* while loading the file.
*
* Description: Load Scream Tracker 3.0 (S3M) music modules from disk.
*
****************************************************************************/
static DSM *S3MLoadModule(int Handle, long Length)
{
DSM *Module;
S3MSong Header;
word SampTab[MAXSAMPLES],PattTab[MAXORDERS];
byte ChanMap[32],PanMap[32],PanPos;
int Index;
if (!(Module = (DSM*)calloc(1,sizeof(DSM)))) {
dError = ERR_NOMEM;
return NULL;
}
if (read(Handle,&Header,sizeof(Header)) != sizeof(Header)) {
dError = ERR_FILEIO;
dFreeModule(Module);
return NULL;
}
if (Header.Magic != S3M_SCRM || Header.NumOrders > MAXORDERS ||
Header.NumPatterns > MAXORDERS || Header.NumSamples > MAXSAMPLES) {
dError = ERR_FORMAT;
dFreeModule(Module);
return NULL;
}
if (read(Handle,Module->Header.Orders,Header.NumOrders) != Header.NumOrders) {
dError = ERR_FILEIO;
dFreeModule(Module);
return NULL;
}
if (read(Handle,SampTab,2*Header.NumSamples) != 2*Header.NumSamples) {
dError = ERR_FILEIO;
dFreeModule(Module);
return NULL;
}
if (read(Handle,PattTab,2*Header.NumPatterns) != 2*Header.NumPatterns) {
dError = ERR_FILEIO;
dFreeModule(Module);
return NULL;
}
if (Header.DefPan == 0xFC) {
if (read(Handle,PanMap,sizeof(PanMap)) != sizeof(PanMap)) {
dError = ERR_FILEIO;
dFreeModule(Module);
return NULL;
}
}
/* fill the SONG structure */
strcpy(Module->Header.ModuleName,Header.SongName);
Module->Header.OrderPos = 0;
Module->Header.ReStart = MAXORDERS-1;
Module->Header.NumOrders = Header.NumOrders;
Module->Header.NumSamples = Header.NumSamples;
Module->Header.NumPatterns = Header.NumPatterns;
Module->Header.GlobalVolume = 64;
Module->Header.MasterVolume = 2*(Header.MasterVolume & 0x7F);
Module->Header.InitTempo = Header.Tempo;
Module->Header.InitBPM = Header.BPM;
Module->Header.NumTracks = 0;
for (Index = 0; Index < 32; Index++) {
Header.ChanMap[Index] &= 0x7F;
ChanMap[Index] = 0xFF;
if (Module->Header.NumTracks >= MAXTRACKS) continue;
else if (Header.ChanMap[Index] <= 15) {
PanPos = (Header.ChanMap[Index] <= 7) ? PAN_LEFT : PAN_RIGHT;
if ((Header.DefPan == 0xFC) && (PanMap[Index] & 0x20))
PanPos = (PanMap[Index] & 0x0F) << 3;
Module->Header.ChanMap[Module->Header.NumTracks] = PanPos;
ChanMap[Index] = (Module->Header.NumTracks)++;
}
}
for (Index = 0; Index < Module->Header.NumOrders; Index++)
if (Module->Header.Orders[Index] == 0xFF) break;
// Module->Header.NumOrders = Index;
/* allocate sample and pattern pointer tables */
if (!(Module->Samples = (Sample**)calloc(Module->Header.NumSamples,sizeof(Sample *)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
if (!(Module->Patterns = (Pattern**)calloc(Module->Header.NumPatterns,sizeof(Pattern *)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
/* fill the PATT structures */
for (Index = 0; Index < Header.NumPatterns; Index++) {
if (!(Module->Patterns[Index] = S3MLoadPattern(Handle,
(dword)PattTab[Index]<<4,ChanMap))) {
dFreeModule(Module);
return NULL;
}
}
/* fill the INST structures */
for (Index = 0; Index < Header.NumSamples; Index++) {
if (!(Module->Samples[Index] = S3MLoadSample(Handle,
(dword)SampTab[Index]<<4))) {
dFreeModule(Module);
return NULL;
}
}
return Module;
}
/*----------------- Multitracker 1.0 Import Routines ----------------------*/
/****************************************************************************
*
* Function: MTMLoadPattern
* Parameters: Seq - track sequence
* Tracks - track structures
*
* Returns: Pattern structure or NULL if error.
*
* Description: Used to build patterns from MTM track sequences.
*
****************************************************************************/
static Pattern *MTMLoadPattern(word *Seq, MTMTrack *Tracks)
{
Pattern *DPatt;
byte *S,*D;
byte Row,Track,Flags,Note,Inst,Effect,Param;
if (!(DPatt = (Pattern*)malloc(2+(1+5*MAXTRACKS)*64))) {
dError = ERR_NOMEM;
return NULL;
}
D = DPatt->Data;
for (Row = 0; Row < 64; Row++) {
for (Track = 0; Track < MAXTRACKS; Track++) {
if (Seq[Track]) {
S = &Tracks[Seq[Track]-1].Data[3*Row];
Note = (S[0] >> 2) & 0x3F;
Inst = ((S[0] & 0x03)<<4) + ((S[1]>>4) & 0x0F);
Effect = (S[1] & 0x0F);
Param = S[2];
Flags = 0;
if (Note) {
Flags |= 0x80;
Note += 12*2+1;
}
if (Inst) Flags |= 0x40;
if (Effect | Param) Flags |= 0x10;
if (Flags) {
*D++ = Flags | (Track & 0x0F);
if (Note) *D++ = Note;
if (Inst) *D++ = Inst;
if (Effect | Param) {
*D++ = Effect;
*D++ = Param;
}
}
}
}
*D++ = 0;
}
DPatt->Length = D-(byte*)DPatt;
return (Pattern*)realloc(DPatt,DPatt->Length);
}
/****************************************************************************
*
* Function: MTMLoadSample
* Parameters: Handle - file handle
* Instr - MTM sample structure
*
* Returns: Sample structure or NULL if error.
*
* Description: Used to load MTM samples.
*
****************************************************************************/
static Sample *MTMLoadSample(int Handle, MTMSample *Instr)
{
Sample *SampPtr;
if (!(SampPtr = LoadSample(Handle,Instr->Length,SF_8BITS|SF_UNSIGNED)))
return NULL;
strncpy(SampPtr->SampleName,Instr->SampleName,sizeof(Instr->SampleName));
SampPtr->Volume = Instr->Volume;
SampPtr->Rate = RateTable[Instr->Finetune & 0x0F];
if (Instr->LoopEnd - Instr->LoopStart > 2) {
SampPtr->Flags |= SF_LOOPED;
SampPtr->LoopStart = Instr->LoopStart;
SampPtr->LoopEnd = Instr->LoopEnd;
}
return SampPtr;
}
/****************************************************************************
*
* Function: MTMLoadModule
* Parameters: Handle - DOS file handle
* Length - file length
*
* Returns: Music module address or NULL when an error has occurred
* while loading the file.
*
* Description: Load Multitracker 1.0 (MTM) music modules from disk.
*
****************************************************************************/
static DSM *MTMLoadModule(int Handle, long Length)
{
DSM *Module;
MTMSong Header;
MTMSample *Samples;
MTMTrack *Tracks;
word TrackSeq[32];
int Index;
/* open MTM module file */
if (!(Module = (DSM*)calloc(1,sizeof(DSM)))) {
dError = ERR_NOMEM;
return NULL;
}
/* load MTM header */
if (read(Handle,&Header,sizeof(Header)) != sizeof(Header)) {
dError = ERR_FILEIO;
dFreeModule(Module);
return NULL;
}
if (((Header.Magic & MTM_MASK) != MTM_MAGIC) ||
(Header.NumChans > MAXTRACKS) ||
// (Header.NumSamples > MAXSAMPLES) ||
(Header.BeatsPerTrack != 64)) {
dError = ERR_FORMAT;
dFreeModule(Module);
return NULL;
}
/* fill the SONG structure */
strncpy(Module->Header.ModuleName,Header.SongName,sizeof(Header.SongName));
Module->Header.OrderPos = 0;
Module->Header.ReStart = MAXORDERS-1;
Module->Header.NumOrders = Header.LastOrder+1;
Module->Header.NumSamples = Header.NumSamples;
Module->Header.NumPatterns = Header.LastPattern+1;
Module->Header.NumTracks = Header.NumChans;
Module->Header.GlobalVolume = 64;
Module->Header.MasterVolume = 768/Module->Header.NumTracks;
Module->Header.InitTempo = 6;
Module->Header.InitBPM = 125;
for (Index = 0; Index < MAXTRACKS; Index++)
Module->Header.ChanMap[Index] = Header.PanPos[Index] << 3;
/* allocate sample and pattern pointer tables */
if (!(Module->Samples = (Sample**)calloc(Module->Header.NumSamples,sizeof(Sample *)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
if (!(Module->Patterns = (Pattern**)calloc(Module->Header.NumPatterns,sizeof(Pattern *)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
/* allocate MTM sample and track structures */
if (!(Samples = (MTMSample*)calloc(Module->Header.NumSamples,sizeof(MTMSample)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
if (!(Tracks = (MTMTrack*)calloc(Header.NumTracks,sizeof(MTMTrack)))) {
dError = ERR_NOMEM;
free(Samples);
dFreeModule(Module);
return NULL;
}
/* load MTM sample structures */
if (read(Handle,Samples,Module->Header.NumSamples*sizeof(MTMSample)) != Module->Header.NumSamples*sizeof(MTMSample)) {
dError = ERR_FILEIO;
free(Tracks);
free(Samples);
dFreeModule(Module);
return NULL;
}
/* load the SONG order list */
if (read(Handle,Module->Header.Orders,128) != 128) {
dError = ERR_FILEIO;
free(Tracks);
free(Samples);
dFreeModule(Module);
return NULL;
}
/* load MTM tracks */
if (read(Handle,Tracks,Header.NumTracks*sizeof(MTMTrack)) != Header.NumTracks*sizeof(MTMTrack)) {
dError = ERR_FILEIO;
free(Tracks);
free(Samples);
dFreeModule(Module);
return NULL;
}
/* fill PATT structures */
for (Index = 0; Index < Module->Header.NumPatterns; Index++) {
if (read(Handle,TrackSeq,sizeof(TrackSeq)) != sizeof(TrackSeq)) {
dError = ERR_FILEIO;
free(Tracks);
free(Samples);
dFreeModule(Module);
return NULL;
}
if (!(Module->Patterns[Index] = MTMLoadPattern(TrackSeq,Tracks))) {
free(Tracks);
free(Samples);
dFreeModule(Module);
return NULL;
}
}
free(Tracks);
/* skip MTM comments data */
if (lseek(Handle,Header.CommentLength,SEEK_CUR) < 0) {
dError = ERR_FILEIO;
free(Samples);
dFreeModule(Module);
return NULL;
}
/* fill INST structures */
for (Index = 0; Index < Module->Header.NumSamples; Index++) {
if (!(Module->Samples[Index] = MTMLoadSample(Handle,&Samples[Index]))) {
free(Samples);
dFreeModule(Module);
return NULL;
}
}
free(Samples);
return Module;
}
/*------------------- Composer 669 Import Routines ------------------------*/
/****************************************************************************
*
* Function: GG9LoadPattern
* Parameters: Handle - file handle
* Tempo - initial tempo value
* BreakRow - number of rows
*
* Returns: Pattern structure or NULL if error.
*
* Description: Used to load 669 patterns.
*
****************************************************************************/
static Pattern *GG9LoadPattern(int Handle, int Tempo, int BreakRow)
{
static byte VolTable[16] = {
0x00,0x06,0x0B,0x10,0x14,0x18,0x1C,0x20,
0x24,0x28,0x2C,0x30,0x34,0x38,0x3C,0x40 };
Pattern *DPatt;
byte *SPatt,*S,*D;
byte Row,Track,Flags,Note,Inst,Volume,Effect,Param;
int InsertTempo, InsertBreak;
if (!(DPatt = (Pattern*)malloc(2+(1+6*8)*64))) {
dError = ERR_NOMEM;
return NULL;
}
if (!(SPatt = (byte*)malloc(3*8*64))) {
dError = ERR_NOMEM;
free(DPatt);
return NULL;
}
if (read(Handle,SPatt,3*8*64) != 3*8*64) {
dError = ERR_FILEIO;
free(SPatt);
free(DPatt);
return NULL;
}
S = SPatt;
D = DPatt->Data;
for (Row = 0; Row < 64; Row++) {
InsertTempo = (Row == 0);
InsertBreak = ((Row == BreakRow) && (Row != 63));
for (Track = 0; Track < 8; Track++) {
Note = (S[0] >> 2);
Inst = ((S[0] & 0x03) << 4) | (S[1] >> 4);
Volume = VolTable[S[1] & 0x0F];
Effect = (S[2] >> 4);
Param = (S[2] & 0x0F);
if (S[0] == 0xFE) {
Note = Inst = 0;
}
else if (S[0] == 0xFF) {
Note = Inst = 0;
Volume = 255;
}
else {
Note++;
Inst++;
}
S += 3;
switch (Effect) {
case 0x0:
Effect = 0x01;
break;
case 0x1:
Effect = 0x02;
break;
case 0x2:
Effect = 0x03;
break;
case 0x3:
Effect = 0x0E;
Param = 0x21;
break;
case 0x4:
Effect = 0x04;
Param = (Param << 4) + 1;
break;
case 0x5:
Effect = 0x0F;
break;
default:
Effect = Param = 0;
break;
}
if (InsertTempo && (!(Effect | Param) || (Track == 7))) {
Effect = 0x0F;
Param = Tempo;
InsertTempo = 0;
}
if (InsertBreak && (!(Effect | Param) || (Track == 7))) {
Effect = 0x0D;
Param = 0x00;
InsertBreak = 0;
}
Flags = 0;
if (Note) {
Note += 12*2;
Flags |= 0x80;
}
if (Inst) Flags |= 0x40;
if (Volume <= 64) Flags |= 0x20;
if (Effect | Param) Flags |= 0x10;
if (Flags) {
*D++ = Flags | (Track & 0x0F);
if (Note) *D++ = Note;
if (Inst) *D++ = Inst;
if (Volume <= 64) *D++ = Volume;
if (Effect | Param) {
*D++ = Effect;
*D++ = Param;
}
}
}
*D++ = 0x00;
}
free(SPatt);
DPatt->Length = D-(byte*)DPatt;
return (Pattern*)realloc(DPatt,DPatt->Length);
}
/****************************************************************************
*
* Function: GG9LoadSample
* Parameters: Handle - file handle
* Instr - 669 sample structure
*
* Returns: Sample structure or NULL if error.
*
* Description: Used to load 669 samples.
*
****************************************************************************/
static Sample *GG9LoadSample(int Handle, GG9Sample *Instr)
{
Sample *SampPtr;
if (!(SampPtr = LoadSample(Handle,Instr->Length,SF_8BITS|SF_UNSIGNED)))
return NULL;
strncpy(SampPtr->SampleName,Instr->FileName,sizeof(Instr->FileName));
SampPtr->Volume = 64;
SampPtr->Rate = MIDCFREQ;
if (Instr->LoopEnd <= Instr->Length) {
SampPtr->Flags |= SF_LOOPED;
SampPtr->LoopStart = Instr->LoopStart;
SampPtr->LoopEnd = Instr->LoopEnd;
}
return SampPtr;
}
/****************************************************************************
*
* Function: GG9LoadModule
* Parameters: Handle - DOS file handle
* Length - file length
*
* Returns: Music module address or NULL when an error has occurred
* while loading the file.
*
* Description: Load Composer 669 music modules from disk.
*
****************************************************************************/
static DSM *GG9LoadModule(int Handle, long Length)
{
DSM *Module;
GG9Song Header;
GG9Sample Samples[64];
int Index;
if (!(Module = (DSM*)calloc(1,sizeof(DSM)))) {
dError = ERR_NOMEM;
return NULL;
}
if (read(Handle,&Header,sizeof(Header)) != sizeof(Header)) {
dError = ERR_FILEIO;
dFreeModule(Module);
return NULL;
}
if (Header.Magic != GG9_MAGIC || Header.NumSamples > 64) {
dError = ERR_FORMAT;
dFreeModule(Module);
return NULL;
}
if (read(Handle,Samples,sizeof(GG9Sample)*Header.NumSamples) != sizeof(GG9Sample)*Header.NumSamples) {
dError = ERR_FILEIO;
dFreeModule(Module);
return NULL;
}
/* fill SONG structure */
strncpy(Module->Header.ModuleName,Header.SongName,sizeof(Module->Header.ModuleName)-1);
Module->Header.OrderPos = 0;
Module->Header.ReStart = Header.ReStart;
Module->Header.NumSamples = Header.NumSamples;
Module->Header.NumPatterns = Header.NumPatterns;
Module->Header.NumTracks = 8;
Module->Header.GlobalVolume = 64;
Module->Header.MasterVolume = 768/8;
Module->Header.InitTempo = 4;
Module->Header.InitBPM = 80;
for (Index = 0; Index < 8; Index++) {
Module->Header.ChanMap[Index] = (Index & 1) ? PAN_RIGHT : PAN_LEFT;
}
for (Index = 0; Index < 128; Index++) {
if (Header.Orders[Index] >= 128) break;
Module->Header.Orders[Index] = Header.Orders[Index];
(Module->Header.NumOrders)++;
}
/* allocate sample and pattern pointer tables */
if (!(Module->Samples = (Sample**)calloc(Module->Header.NumSamples,sizeof(Sample *)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
if (!(Module->Patterns = (Pattern**)calloc(Module->Header.NumPatterns,sizeof(Pattern *)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
/* load PATT structures */
for (Index = 0; Index < Module->Header.NumPatterns; Index++) {
if (!(Module->Patterns[Index] = GG9LoadPattern(Handle,
Header.Tempos[Index],Header.Breaks[Index]))) {
dFreeModule(Module);
return NULL;
}
}
/* load INST structures */
for (Index = 0; Index < Module->Header.NumSamples; Index++) {
if (!(Module->Samples[Index] = GG9LoadSample(Handle,&Samples[Index]))) {
dFreeModule(Module);
return NULL;
}
}
return Module;
}
/*-------------------- Scream Tracker 2.0 import routines -----------------*/
/****************************************************************************
*
* Function: STMLoadPattern
* Parameters: Handle - file handle
*
* Returns: Pattern structure or NULL if error.
*
* Description: Used to load STM patterns.
*
****************************************************************************/
static Pattern *STMLoadPattern(int Handle)
{
Pattern *DPatt;
byte *SPatt,*S,*D;
byte Row,Track,Flags,Note,Inst,Volume,Effect,Param;
if (!(DPatt = (Pattern*)malloc(2+(1+6*4)*64))) {
dError = ERR_NOMEM;
return NULL;
}
if (!(SPatt = (byte*)malloc(4*4*64))) {
dError = ERR_NOMEM;
free(DPatt);
return NULL;
}
if (read(Handle,SPatt,4*4*64) != 4*4*64) {
dError = ERR_FILEIO;
free(SPatt);
free(DPatt);
return NULL;
}
S = SPatt;
D = DPatt->Data;
for (Row = 0; Row < 64; Row++) {
for (Track = 0; Track < 4; Track++) {
Note = S[0];
Inst = S[1] >> 3;
Volume = (S[1] & 0x07) | ((S[2] & 0xF0) >> 1);
Effect = 64 + (S[2] & 0x0F);
Param = S[3];
S += 4;
if (Note >= 251) continue;
Note = (Note & 0x0F) + 12*(Note >> 4);
switch (Effect) {
case 'A':
Effect = 0x0F;
Param >>= 4;
break;
case 'B':
Effect = 0x0B;
break;
case 'C':
Effect = 0x0D;
break;
case 'D':
if ((Param & 0xF0) == 0x00) {
Effect = 0x0A;
Param &= 0x0F;
}
else if ((Param & 0x0F) == 0x00) {
Effect = 0x0A;
Param &= 0xF0;
}
else {
Effect = Param = 0;
}
break;
case 'E':
Effect = 0x02;
break;
case 'F':
Effect = 0x01;
break;
case 'G':
Effect = 0x03;
break;
case 'H':
Effect = 0x04;
break;
case 'I':
Effect = 0x0E; /* emu tremor with retrig */
Param = 0x90 | (Param & 0x0F);
break;
case 'J':
Effect = 0x00;
break;
default:
Effect = Param = 0;
break;
}
Flags = 0;
if (Note) {
Note += 2*12;
Flags |= 0x80;
}
if (Inst) Flags |= 0x40;
if (Volume <= 64) Flags |= 0x20;
if (Effect | Param) Flags |= 0x10;
if (Flags) {
*D++ = Flags | (Track & 0x0F);
if (Note) *D++ = Note;
if (Inst) *D++ = Inst;
if (Volume <= 64) *D++ = Volume;
if (Effect | Param) {
*D++ = Effect;
*D++ = Param;
}
}
}
*D++ = 0x00;
}
free(SPatt);
DPatt->Length = D-(byte*)DPatt;
return (Pattern*)realloc(DPatt,DPatt->Length);
}
/****************************************************************************
*
* Function: STMLoadSample
* Parameters: Handle - file handle
* Instr - STM sample structure
*
* Returns: Sample structure or NULL if error.
*
* Description: Used to load STM samples.
*
****************************************************************************/
static Sample *STMLoadSample(int Handle, STMSample *Instr)
{
Sample *SampPtr;
if (!(SampPtr = LoadSample(Handle,Instr->Length,SF_8BITS|SF_SIGNED)))
return NULL;
strncpy(SampPtr->SampleName,Instr->FileName,sizeof(Instr->FileName));
SampPtr->Volume = Instr->Volume;
SampPtr->Rate = Instr->Rate;
if (Instr->LoopEnd <= Instr->Length) {
SampPtr->Flags |= SF_LOOPED;
SampPtr->LoopStart = Instr->LoopStart;
SampPtr->LoopEnd = Instr->LoopEnd;
}
return SampPtr;
}
/****************************************************************************
*
* Function: STMLoadModule
* Parameters: Handle - DOS file handle
* Length - file length
*
* Returns: Music module address or NULL when an error has occurred
* while loading the file.
*
* Description: Load Scream Tracker 2.0 (STM) music modules from disk.
*
****************************************************************************/
static DSM *STMLoadModule(int Handle, long Length)
{
DSM *Module;
STMSong Header;
int Index;
if (!(Module = (DSM*)calloc(1,sizeof(DSM)))) {
dError = ERR_NOMEM;
return NULL;
}
if (read(Handle,&Header,sizeof(Header)) != sizeof(Header)) {
dError = ERR_FILEIO;
dFreeModule(Module);
return NULL;
}
if (memcmp(Header.Tracker,STM_TRACKER,sizeof(Header.Tracker))) {
dError = ERR_FORMAT;
dFreeModule(Module);
return NULL;
}
/* fill SONG structure */
strncpy(Module->Header.ModuleName,Header.SongName,sizeof(Header.SongName));
Module->Header.OrderPos = 0;
Module->Header.ReStart = MAXORDERS-1;
Module->Header.NumSamples = 31;
Module->Header.NumPatterns = Header.NumPatterns;
Module->Header.NumTracks = 4;
Module->Header.GlobalVolume = 64;
Module->Header.MasterVolume = 768/4;
Module->Header.InitTempo = Header.InitTempo >> 4;
Module->Header.InitBPM = 125;
for (Index = 0; Index < 128; Index++) {
if (Header.Orders[Index] >= 99) break;
Module->Header.Orders[Index] = Header.Orders[Index];
(Module->Header.NumOrders)++;
}
for (Index = 0; Index < 4; Index++) {
Module->Header.ChanMap[Index] = (Index & 1) ? PAN_RIGHT : PAN_LEFT;
}
/* allocate sample and pattern pointer tables */
if (!(Module->Samples = (Sample**)calloc(Module->Header.NumSamples,sizeof(Sample *)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
if (!(Module->Patterns = (Pattern**)calloc(Module->Header.NumPatterns,sizeof(Pattern *)))) {
dError = ERR_NOMEM;
dFreeModule(Module);
return NULL;
}
/* load PATT structures */
for (Index = 0; Index < Module->Header.NumPatterns; Index++) {
if (!(Module->Patterns[Index] = STMLoadPattern(Handle))) {
dFreeModule(Module);
return NULL;
}
}
/* load INST structures */
for (Index = 0; Index < Module->Header.NumSamples; Index++) {
if (!(Module->Samples[Index] = STMLoadSample(Handle,&Header.Samples[Index]))) {
dFreeModule(Module);
return NULL;
}
}
return Module;
}
/*------------------- Module/Sample Import Routines -----------------------*/
/****************************************************************************
*
* Function: dImportModuleFile
* Parameters: Handle - DOS file handle
* Length - Module length
* Form - Module format
*
* Returns: Music module address or NULL when an error has occurred
* while loading the file.
*
* Description: Load multichannel music modules from disk.
*
****************************************************************************/
DSM *dImportModuleFile(int Handle, long Length, int Form)
{
return (Form == FORM_DSM) ? dLoadModuleFile(Handle,Length) :
(Form == FORM_MOD) ? MODLoadModule(Handle,Length) :
(Form == FORM_S3M) ? S3MLoadModule(Handle,Length) :
(Form == FORM_MTM) ? MTMLoadModule(Handle,Length) :
(Form == FORM_669) ? GG9LoadModule(Handle,Length) :
(Form == FORM_STM) ? STMLoadModule(Handle,Length) :
NULL;
}
/****************************************************************************
*
* Function: dImportSampleFile
* Parameters: Filename - Sample filename
* Length - Sample length
* Form - Sample format
*
* Returns: Sample address or NULL when an error has occurred
* while loading the file.
*
* Description: Load 8-bit mono digital samples from disk.
*
****************************************************************************/
Sample *dImportSampleFile(int Handle, long Length, int Form)
{
return (Form == FORM_WAV) ? dLoadSampleFile(Handle,Length) :
(Form == FORM_VOC) ? VOCLoadSample(Handle,Length) :
(Form == FORM_IFF) ? IFFLoadSample(Handle,Length) :
(Form == FORM_RAW) ? RAWLoadSample(Handle,Length) :
NULL;
}
/****************************************************************************
*
* Function: dImportModule
* Parameters: Filename - Module filename
* Form - Module format
*
* Returns: Music module address or NULL when an error has occurred
* while loading the file.
*
* Description: Load multichannel music modules from disk.
*
****************************************************************************/
DSM *dImportModule(char *Filename, int Form)
{
int Handle;
DSM *Module;
long Length;
if ((Handle = open(Filename,O_RDONLY|O_BINARY)) < 0) {
dError = ERR_NOFILE;
return NULL;
}
if ((Length = filelength(Handle)) < 0) {
dError = ERR_FILEIO;
close(Handle);
return NULL;
}
Module = dImportModuleFile(Handle,Length,Form);
close(Handle);
return Module;
}
/****************************************************************************
*
* Function: dImportSample
* Parameters: Filename - Sample filename
* Form - Sample format
*
* Returns: Sample address or NULL when an error has occurred
* while loading the file.
*
* Description: Load 8-bit mono digital samples from disk.
*
****************************************************************************/
Sample *dImportSample(char *Filename, int Form)
{
int Handle;
Sample *SampPtr;
long Length;
if ((Handle = open(Filename,O_RDONLY|O_BINARY)) < 0) {
dError = ERR_NOFILE;
return NULL;
}
if ((Length = filelength(Handle)) < 0) {
dError = ERR_FILEIO;
close(Handle);
return NULL;
}
SampPtr = dImportSampleFile(Handle,Length,Form);
close(Handle);
return SampPtr;
}