home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 24
/
CD_ASCQ_24_0995.iso
/
dos
/
prg
/
dsik205
/
dsik.dat
/
EXAMPLES
/
M2DSM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-10
|
22KB
|
645 lines
/****************************************************************************
*
* Digital Sound Interface Kit (DSIK)
* Version 2.00
*
* by Carlos Hasan
*
* Filename: m2dsm.c
* Version: Revision 1.1
*
* Language: WATCOM C
* Environment: IBM PC (DOS/4GW)
*
* Description: Standalone music module converter.
*
* Revision History:
* ----------------
*
* Revision 1.1 94/12/28 18:40:45 chv
* New unused tracks removal routine.
*
* Revision 1.0 94/10/01 18:47:07 chv
* Initial revision
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
#include <malloc.h>
#include <string.h>
#include <sys\stat.h>
#include "audio.h"
#include "import.h"
/****************************************************************************
*
* Functions: dGetDriverFlags, dMemAlloc and dMemFree
*
* Description: Fake sound system functions used to load modules in memory.
*
****************************************************************************/
int dGetDriverFlags(void)
{
return AF_8BITS | AF_MONO | AF_NODRAM;
}
long dMemAlloc(Sample *SampPtr)
{
return (long)SampPtr;
}
void dMemFree(Sample *SampPtr)
{
}
/****************************************************************************
*
* Function: dSaveModule
* Parameters: Filename - DOS file name
* Module - Music module
*
* Returns: Music module or NULL if error.
*
****************************************************************************/
DSM *dSaveModule(char *Filename, DSM *Module)
{
int Handle,I;
RiffHeader Header;
RiffBlock Block;
if ((Handle = open(Filename,O_CREAT|O_WRONLY|O_BINARY,S_IRWXU)) < 0)
return NULL;
Header.ID = ID_RIFF;
Header.Length = sizeof(Header.Type) + sizeof(Block) + sizeof(Song);
Header.Type = ID_DSMF;
for (I = 0; I < Module->Header.NumPatterns; I++)
Header.Length += sizeof(Block) + Module->Patterns[I]->Length;
for (I = 0; I < Module->Header.NumSamples; I++)
Header.Length += sizeof(Block) + sizeof(Sample) + Module->Samples[I]->Length;
if (write(Handle,&Header,sizeof(Header)) != sizeof(Header)) {
close(Handle);
return NULL;
}
Block.ID = ID_SONG;
Block.Length = sizeof(Song);
if (write(Handle,&Block,sizeof(Block)) != sizeof(Block)) {
close(Handle);
return NULL;
}
if (write(Handle,&Module->Header,Block.Length) != Block.Length) {
close(Handle);
return NULL;
}
for (I = 0; I < Module->Header.NumPatterns; I++) {
Block.ID = ID_PATT;
Block.Length = Module->Patterns[I]->Length;
if (write(Handle,&Block,sizeof(Block)) != sizeof(Block)) {
close(Handle);
return NULL;
}
if (write(Handle,Module->Patterns[I],Block.Length) != Block.Length) {
close(Handle);
return NULL;
}
}
for (I = 0; I < Module->Header.NumSamples; I++) {
Block.ID = ID_INST;
Block.Length = sizeof(Sample) + Module->Samples[I]->Length;
if (write(Handle,&Block,sizeof(Block)) != sizeof(Block)) {
close(Handle);
return NULL;
}
if (write(Handle,Module->Samples[I],sizeof(Sample)) != sizeof(Sample)) {
close(Handle);
return NULL;
}
if (write(Handle,Module->Samples[I]->DataPtr,Module->Samples[I]->Length) != Module->Samples[I]->Length) {
close(Handle);
return NULL;
}
}
close(Handle);
return Module;
}
/****************************************************************************
*
* Function: dSaveSample
* Parameters: Filename - DOS file name
* SampPtr - sample structure
*
* Returns: Sample structure or NULL if error.
*
****************************************************************************/
Sample *dSaveSample(char *Filename, Sample *SampPtr)
{
int Handle;
if ((Handle = open(Filename,O_CREAT|O_WRONLY|O_BINARY,S_IRWXU)) < 0)
return NULL;
if (write(Handle,SampPtr->DataPtr,SampPtr->Length) != SampPtr->Length) {
close(Handle);
return NULL;
}
close(Handle);
return SampPtr;
}
/****************************************************************************
*
* Function: dDumpModule
* Parameters: Module - Music module
*
* Description: Dump module information on screen.
*
****************************************************************************/
void dDumpModule(DSM *Module)
{
int I;
printf( "\nRIFF/DSMF Module File:\n"
"\n"
"Module name \"%s\"\n"
"Order list length %d\n"
"Number of patterns %d\n"
"Number of samples %d\n"
"Number of tracks %d\n"
"Global/Master volume %d/%d\n"
"Initial speed/tempo %d/%d\n",
Module->Header.ModuleName,
Module->Header.NumOrders,
Module->Header.NumPatterns,
Module->Header.NumSamples,
Module->Header.NumTracks,
Module->Header.GlobalVolume,
Module->Header.MasterVolume,
Module->Header.InitTempo,
Module->Header.InitBPM);
printf( "\n"
"Instrument table:\n"
"\n");
for (I = 0; I < Module->Header.NumSamples; I++) {
printf( "Sample %d:\n"
" Instrument name \"%s\"\n"
" Middle-c frequency %d Hz\n"
" Default volume %d\n"
" Sample length %ld\n"
" Loop start/end points %ld/%ld\n"
" Bit flags 0x%02x ( %s%s%s%s%s )\n\n",
I+1,
Module->Samples[I]->SampleName,
Module->Samples[I]->Rate,
Module->Samples[I]->Volume,
Module->Samples[I]->Length,
Module->Samples[I]->LoopStart,
Module->Samples[I]->LoopEnd,
Module->Samples[I]->Flags,
Module->Samples[I]->Flags & SF_16BITS ? "16-BIT" : "8-BIT",
Module->Samples[I]->Flags & SF_SIGNED ? " SIGNED" : " UNSIGNED",
Module->Samples[I]->Flags & SF_DELTA ? " DELTA" : "",
Module->Samples[I]->Flags & SF_LOOPED ? " LOOPED" : "",
Module->Samples[I]->Flags & SF_LIBRARY ? " LIBRARY" : "");
}
printf("\n");
}
/****************************************************************************
*
* Function: dOptPattern
* Parameters: Patt - pattern pointer
* TrkUsed - tracks used array
* SmpUsed - samples used array
* Hdr - module header
*
* Description: Optimize and check music pattern.
*
****************************************************************************/
void dOptPattern(Pattern *Patt, int *TrkUsed, int *SmpUsed, Song *Hdr)
{
unsigned char *ptr,*endptr;
unsigned row,track,flags,sample;
if (!Patt) {
printf("FATAL ERROR: null pattern address!\n");
exit(EXIT_FAILURE);
}
ptr = Patt->Data;
endptr = ((char*)Patt)+Patt->Length;
for (row = 0; row < 64; row++) {
while ((flags = *ptr++) != 0) {
if (ptr >= endptr) {
printf("FATAL ERROR: pattern is corrupted!\n");
exit(EXIT_FAILURE);
}
track = flags & 0x0F;
TrkUsed[track] = 1;
if (flags & 0x80) {
if (*ptr > 96) {
printf("WARNING: invalid note index (%d).\n",*ptr);
*ptr = 0;
}
ptr++;
}
if (flags & 0x40) {
if ((sample = *ptr) > Hdr->NumSamples) {
printf("WARNING: invalid sample reference (%d).\n",sample);
*ptr = 0;
}
else SmpUsed[sample] = 1;
ptr++;
}
if (flags & 0x20) {
if (*ptr > 64) {
printf("WARNING: invalid volume level (%d).\n",*ptr);
*ptr = 64;
}
ptr++;
}
if (flags & 0x10) {
if (*ptr >= 16) {
printf("WARNING: invalid protracker command (%1x%02x).\n",ptr[0],ptr[1]);
*ptr++ = 0;
*ptr++ = 0;
}
else ptr += 2;
}
}
}
}
/****************************************************************************
*
* Function: dMapPattern
* Parameters: Patt - pattern pointer
* TrkMap - tracks remap table
*
* Description: Remap tracks in a pattern sheet.
*
****************************************************************************/
void dMapPattern(Pattern *Patt, int *TrkMap)
{
unsigned char *ptr;
unsigned row,flags;
ptr = Patt->Data;
for (row = 0; row < 64; row++) {
while ((flags = *ptr) != 0) {
*ptr++ = (flags & 0xF0) | (TrkMap[flags & 0x0F] & 0x0F);
if (flags & 0x80) ptr++;
if (flags & 0x40) ptr++;
if (flags & 0x20) ptr++;
if (flags & 0x10) ptr += 2;
}
}
}
/****************************************************************************
*
* Function: dOptSample
* Parameters: SampPtr - sample structure
* Packed - delta packed sample flag
*
* Description: Optimize and check sample structures.
*
****************************************************************************/
void dOptSample(Sample *SampPtr, int Packed)
{
long count;
signed char *ptr,oldsample,newsample;
if (!SampPtr->Length) {
/* clear sample information if there is no data */
SampPtr->Flags = 0;
SampPtr->Volume = 0;
SampPtr->LoopStart = SampPtr->LoopEnd = 0;
SampPtr->Rate = 0;
}
if (SampPtr->Length && !(SampPtr->Flags & SF_SIGNED)) {
/* the sound system likes signed samples :-) */
count = SampPtr->Length;
ptr = (signed char *)SampPtr->DataPtr;
while (count--) *ptr++ ^= 0x80;
SampPtr->Flags |= SF_SIGNED;
}
if (SampPtr->Length && Packed) {
count = SampPtr->Length;
ptr = (signed char *)SampPtr->DataPtr;
oldsample = 0;
while (count--) {
newsample = *ptr;
*ptr++ -= oldsample;
oldsample = newsample;
}
SampPtr->Flags |= SF_DELTA;
}
if (SampPtr->Volume > 64) {
printf("WARNING: invalid sample default volume (%d).\n", SampPtr->Volume);
SampPtr->Volume = 64;
}
if (SampPtr->Flags & SF_LOOPED) {
if (SampPtr->LoopEnd > SampPtr->Length) {
printf("WARNING: invalid sample loop end point.\n");
SampPtr->LoopEnd = SampPtr->Length;
}
if (SampPtr->LoopStart > SampPtr->LoopEnd) {
printf("WARNING: invalid sample loop start point.\n");
SampPtr->LoopStart = SampPtr->LoopEnd;
}
}
else {
SampPtr->LoopStart = SampPtr->LoopEnd = 0;
}
if ((SampPtr->Rate < 4000) && (SampPtr->Length)) {
printf("WARNING: invalid sample frequency.\n");
SampPtr->Rate = MIDCFREQ;
}
}
/****************************************************************************
*
* Function: dOptModule
* Parameters: Module - Music module
* Packed - samples delta packed flag
* ReMap - track remap flag
*
* Description: Optimize and check music module.
*
****************************************************************************/
void dOptModule(DSM *Module, int Packed, int Remap)
{
static int PtnUsed[MAXORDERS],PtnMap[MAXORDERS];
static int TrkUsed[MAXTRACKS],TrkMap[MAXTRACKS];
static int SmpUsed[MAXSAMPLES+1];
int I,J;
/* check out the module header */
if (strlen(Module->Header.ModuleName) >= sizeof(Module->Header.ModuleName)) {
printf("FATAL ERROR: module header is corrupted!\n");
exit(EXIT_FAILURE);
}
if (Module->Header.NumOrders == 0 || Module->Header.NumOrders > MAXORDERS) {
printf("FATAL ERROR: invalid orderlist length!\n");
exit(EXIT_FAILURE);
}
if (Module->Header.NumSamples > MAXSAMPLES) {
printf("FATAL ERROR: too many samples!\n");
exit(EXIT_FAILURE);
}
if (Module->Header.NumPatterns > MAXORDERS) {
printf("FATAL ERROR: too many patterns!\n");
exit(EXIT_FAILURE);
}
if (Module->Header.NumTracks == 0 || Module->Header.NumTracks > MAXTRACKS) {
printf("FATAL ERROR: invalid number of tracks!\n");
exit(EXIT_FAILURE);
}
if (Module->Header.GlobalVolume > 64 || Module->Header.MasterVolume < 16) {
printf("FATAL ERROR: invalid global/master volume!\n");
exit(EXIT_FAILURE);
}
if (Module->Header.InitTempo >= 32 || Module->Header.InitBPM < 32) {
printf("FATAL ERROR: invalid speed/tempo!\n");
exit(EXIT_FAILURE);
}
/* search used and unused patterns */
memset(PtnUsed,0,sizeof(PtnUsed));
for (I = 0; I < Module->Header.NumOrders; I++) {
if ((J = Module->Header.Orders[I]) < Module->Header.NumPatterns)
PtnUsed[J] = 1;
else if (J != 0xFF) {
printf("WARNING: invalid pattern reference (%d).\n",J);
}
}
/* build the pattern remap table and update the order list */
for (I = J = 0; I < MAXORDERS; I++)
PtnMap[I] = PtnUsed[I] ? J++ : 0xFF;
for (I = 0; I < MAXORDERS; I++) {
if (I < Module->Header.NumOrders) {
if ((J = Module->Header.Orders[I]) < Module->Header.NumPatterns) {
Module->Header.Orders[I] = PtnMap[J];
}
else {
Module->Header.Orders[I] = 0xFF;
}
}
else {
Module->Header.Orders[I] = 0xFF;
}
}
/* free unused patterns and remap pattern array */
for (I = 0; I < Module->Header.NumPatterns; I++) {
if (PtnUsed[I]) {
Module->Patterns[PtnMap[I]] = Module->Patterns[I];
}
else {
free(Module->Patterns[I]);
Module->Patterns[I] = NULL;
}
}
/* update number of patterns field */
for (I = 0; I < Module->Header.NumPatterns; I++)
if (!Module->Patterns[I]) break;
if (I == 0) {
printf("FATAL ERROR: no patterns in module!\n");
exit(EXIT_FAILURE);
}
if (I < Module->Header.NumPatterns) {
printf("WARNING: removing %d unused pattern(s).\n", Module->Header.NumPatterns-I);
Module->Header.NumPatterns = I;
}
/* update order list length */
for (I = J = 0; I < Module->Header.NumOrders; I++)
if (Module->Header.Orders[I] != 0xFF) J = I+1;
if (J < Module->Header.NumOrders) {
printf("WARNING: removing %d unused order(s).\n",Module->Header.NumOrders-J);
Module->Header.NumOrders = J;
}
/* optimize and check sample structures */
for (I = 0; I < Module->Header.NumSamples; I++) {
dOptSample(Module->Samples[I],Packed);
}
/* optimize and check patterns and search used/unused samples */
memset(TrkUsed,0,sizeof(TrkUsed));
memset(SmpUsed,0,sizeof(SmpUsed));
for (I = 0; I < Module->Header.NumPatterns; I++) {
dOptPattern(Module->Patterns[I],TrkUsed,SmpUsed,&Module->Header);
}
/* remove unused samples */
for (I = J = 0; I < Module->Header.NumSamples; I++) {
if (!SmpUsed[I+1] && Module->Samples[I]->Length) {
if (Module->Samples[I]->DataPtr) free(Module->Samples[I]->DataPtr);
Module->Samples[I]->DataPtr = NULL;
Module->Samples[I]->Flags = 0;
Module->Samples[I]->Volume = 0;
Module->Samples[I]->Length = 0;
Module->Samples[I]->LoopStart = Module->Samples[I]->LoopEnd = 0;
Module->Samples[I]->Rate = 0;
J++;
}
}
if (J) {
printf("WARNING: removing %d unused sample(s).\n",J);
}
/* remove unused tracks */
if (Remap) {
for (I = J = 0; I < MAXTRACKS; I++)
TrkMap[I] = TrkUsed[I] ? J++ : 0xFF;
if (Module->Header.NumTracks != J)
printf("WARNING: removing %d unused track(s).\n", Module->Header.NumTracks-J);
Module->Header.NumTracks = J;
for (I = 0; I < MAXTRACKS; I++) {
if (TrkMap[I] != 0xFF)
Module->Header.ChanMap[TrkMap[I]] =
Module->Header.ChanMap[I];
}
for (I = Module->Header.NumTracks; I < MAXTRACKS; I++)
Module->Header.ChanMap[I] = 0xFF;
for (I = 0; I < Module->Header.NumPatterns; I++)
dMapPattern(Module->Patterns[I],TrkMap);
}
}
int main(int argc, char *argv[])
{
DSM *module;
Sample *sample;
char path[_MAX_PATH],drive[_MAX_DRIVE];
char dir[_MAX_DIR],name[_MAX_FNAME],ext[_MAX_EXT];
int verbose,looped,packed,remap,form,i;
printf("M2DSM Version 2.01 Copyright (C) 1995 Carlos Hasan\n");
verbose = looped = packed = remap = 0;
strcpy(path,"");
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i],"-v")) verbose = 1;
else if (!strcmp(argv[i],"-l")) looped = 1;
else if (!strcmp(argv[i],"-p")) packed = 1;
else if (!strcmp(argv[i],"-t")) remap = 1;
else if (!strlen(path)) strcpy(path,argv[i]);
}
if (strlen(path) == 0) {
printf( "use: M2DSM [options] file[.mod|.s3m|.mtm|.669|.stm|.wav|.voc|.iff|.raw]\n"
"options:\n"
" -v verbose mode\n"
" -l enable looping on modules\n"
" -p delta pack sample data\n"
" -t remove unused tracks\n"
"M2DSM convert MOD, S3M, MTM, 669, STM and DSM to RIFF/DSMF module files\n"
"and WAV, VOC, IFF and RAW to 8-bit signed RAW sample files.\n");
exit(EXIT_FAILURE);
}
strupr(path);
_splitpath(path,drive,dir,name,ext);
if (*ext == 0) strcpy(ext,".MOD");
_makepath(path, drive, dir, name, ext);
if (!strcmp(ext,".DSM")) form = FORM_DSM;
else if (!strcmp(ext,".MOD")) form = FORM_MOD;
else if (!strcmp(ext,".S3M")) form = FORM_S3M;
else if (!strcmp(ext,".MTM")) form = FORM_MTM;
else if (!strcmp(ext,".669")) form = FORM_669;
else if (!strcmp(ext,".STM")) form = FORM_STM;
else if (!strcmp(ext,".WAV")) form = FORM_WAV;
else if (!strcmp(ext,".VOC")) form = FORM_VOC;
else if (!strcmp(ext,".IFF")) form = FORM_IFF;
else {
printf("FATAL ERROR: unknown module/sample file format (%s).\n",path);
exit(EXIT_FAILURE);
}
if (form < FORM_WAV) {
printf("Loading %s module file: %s\n",
form == FORM_DSM ? "RIFF/DSMF" :
form == FORM_MOD ? "Protracker/Fastracker" :
form == FORM_S3M ? "Scream Tracker 3.0" :
form == FORM_MTM ? "Multitracker 1.0" :
form == FORM_669 ? "Composer 669" :
form == FORM_STM ? "Scream Tracker 2.0" : "", path);
if (!(module = dImportModule(path,form))) {
printf("FATAL ERROR (%03d): cannot load %s module file: %s.\n",
dError, path, dErrorMsg[dError]);
exit(EXIT_FAILURE);
}
/* optimze and check module */
dOptModule(module,packed,remap);
if (looped) {
if ((module->Header.ReStart < module->Header.NumOrders) &&
(module->Header.ReStart != 0))
printf("WARNING: restart position modified.\n");
module->Header.ReStart = 0;
}
strupr(path);
_makepath(path, "", "", name, ".DSM");
printf("Saving RIFF/DSMF module file: %s\n",path);
if (!dSaveModule(path,module)) {
printf("FATAL ERROR: cannot create/write file: %s\n",path);
exit(EXIT_FAILURE);
}
if (verbose) dDumpModule(module);
}
else {
printf("Loading %s sample file: %s\n",
form == FORM_WAV ? "Microsoft WAVE" :
form == FORM_VOC ? "Creative Labs Voice" :
form == FORM_IFF ? "Amiga IFF/8SVX" : "", path);
if (!(sample = dImportSample(path,form))) {
printf("FATAL ERROR (%03d): cannot load %s sample file: %s.\n",
dError, path, dErrorMsg[dError]);
exit(EXIT_FAILURE);
}
/* optimze and check sample */
dOptSample(sample,packed);
strupr(path);
_makepath(path, "", "", name, ".RAW");
printf("Saving 8-bit signed RAW sample file: %s\n",path);
if (!dSaveSample(path,sample)) {
printf("FATAL ERROR: cannot create/write file: %s\n",path);
exit(EXIT_FAILURE);
}
}
return EXIT_SUCCESS;
}