1 /* Copyright (c) 2003-2021 James Daniels */
2 /* Distributed under the MIT License */
3 /* license terms: see LICENSE file in root or http://opensource.org/licenses/MIT */
6 /* + Max number of MODs = 256 */
7 /* + Max total size of all samples = 33,554,432 bytes */
8 /* + Max total size of all patterns = 33,554,432 bytes */
9 /* + All functions declared static to work around problem with GCC */
17 #define BYTE signed char
18 #define UBYTE unsigned char
19 #define BOOL unsigned char
20 #define UWORD unsigned short
21 #define ULONG unsigned int
22 #define WORD signed short
26 __inline static int Min(int a, int b)
34 __inline static UWORD SwapUWORD( UWORD a )
36 return (a>>8)+((a&0xff)<<8);
39 static int memcmp_new( UBYTE* a, UBYTE* b, int length )
41 for(; length > 0; --length )
48 static void memcpy_new( UBYTE* dest, UBYTE* source, int length )
50 for(; length > 0; --length )
54 #define MAX_DATA_LENGTH 33554432
55 typedef struct data_pack
57 const char* chunk_name;
58 int chunk_data_length;
61 unsigned char chunk_data[MAX_DATA_LENGTH];
64 static DATAPACK* DATA_Create( const char* name )
66 DATAPACK* new_data = (DATAPACK*)malloc(sizeof(DATAPACK));
70 /*printf( "DATA_Create( %s ): addr:%p\n", name, new_data ); */
72 new_data->chunk_name = name;
73 new_data->chunk_data_length = 0;
74 new_data->chunk_unique = 0;
75 new_data->chunk_actual = 0;
79 printf( "DATA_Create( %s ): Failed (address:%p length:%d)...\n", name, (void*)new_data, (int)sizeof(DATAPACK) );
85 static int DATA_AppendAligned( DATAPACK* curr_data, unsigned char* data, int length, int block_length )
87 ++curr_data->chunk_actual;
89 if ( (block_length*((int)(length/block_length))) != length )
91 printf( "DATA_AppendAligned( %p, %p, %d, %d ): Warning length not exactly divisible by block_length!\n",
92 (void*)curr_data, data, length, block_length );
95 else if ( length == 0 )
103 while ( (offset + block_length) <= curr_data->chunk_data_length )
105 if ( memcmp( data, curr_data->chunk_data + offset, length ) == 0 )
107 return offset/block_length;
110 offset += block_length;
113 if ( curr_data->chunk_data_length <= (MAX_DATA_LENGTH-length) )
115 memcpy( curr_data->chunk_data + offset, data, length );
116 curr_data->chunk_data_length += length;
117 ++curr_data->chunk_unique;
118 return offset/block_length;
122 --curr_data->chunk_actual;
123 printf( "DATA_AppendAligned( %p, %p, %d, %d ): Data >%d bytes!\n",
124 (void*)curr_data, data, length, block_length, MAX_DATA_LENGTH );
130 static int DATA_Append( DATAPACK* curr_data, unsigned char* data, int length )
132 ++curr_data->chunk_actual;
142 while ( (offset + length) <= curr_data->chunk_data_length )
144 if ( memcmp_new( data, curr_data->chunk_data + offset, length ) == 0 )
149 if ( curr_data->chunk_data_length <= (MAX_DATA_LENGTH-length) )
151 offset = curr_data->chunk_data_length;
152 memcpy_new( curr_data->chunk_data + offset, data, length );
153 curr_data->chunk_data_length += length;
154 ++curr_data->chunk_unique;
159 --curr_data->chunk_actual;
160 printf( "DATA_Append( %p, %d ): Data >%d bytes!\n", data, length, MAX_DATA_LENGTH );
166 static void DATA_Write( DATAPACK* curr_data, FILE* out_file )
171 len = curr_data->chunk_data_length;
178 printf( "Writing %s (Unique:%d Actual:%d Length:%d)...", curr_data->chunk_name, curr_data->chunk_unique, curr_data->chunk_actual, len );
180 fprintf( out_file, "\n.ALIGN\n.GLOBAL %s\n%s:\n.byte", curr_data->chunk_name, curr_data->chunk_name );
184 for( i = 0; i < len; ++i )
186 if ( i >= curr_data->chunk_data_length )
189 val = *(curr_data->chunk_data + i);
191 fprintf( out_file, " %d", val );
193 fprintf( out_file, ", %d", val );
195 fprintf( out_file, "\n" );
199 fprintf( out_file, " 0\n" );
209 UWORD repeat; /* in halfwords */
210 UWORD length; /* in halfwords */
211 UWORD truelen; /* in halfwords */
218 ULONG data; /* offset in bytes */
219 UWORD repeat; /* in halfwords */
220 UWORD length; /* in halfwords */
225 static void MISC_ProcessSound( BYTE* data, int length )
227 for(; length > 0; --length )
238 static void MISC_ConvSoundToSigned( UBYTE* data, int length )
240 BYTE* bdata = (BYTE*)data;
241 for(; length > 0; --length )
249 static void MOD_LoadSound( struct ModSample* smp, FILE* in_file, DATAPACK* samples, int length, int truelen, int repeat )
251 BYTE* samp = malloc( (length<<1)+16 );
254 fread( samp+16, (length<<1), 1, in_file );
258 memset( samp, 0, 16 );
259 if ( (repeat < 65535) && (truelen > repeat) )
260 memcpy( samp+(repeat<<1), samp+(truelen<<1), 16 ); /* should really merge, also wasteful of memory */
261 MISC_ProcessSound( samp, (truelen<<1)+16 );
262 data = DATA_Append( samples, (UBYTE*)samp, (truelen<<1)+16 );
269 smp->length = truelen;
276 static struct ModSample samps[MAX_MODS][31];
277 static WORD patts[MAX_MODS][128][16]; /* [mod][pattern][channel] */
278 static UBYTE mod_num_chans[MAX_MODS];
279 static UBYTE mod_song_restart_pos[MAX_MODS];
280 static int max_song_length = 0;
282 static const char* effect_name[32] = { "*0: Arpeggio", "*1: Slide Up", "*2: Slide Down", "*3: Tone Portamento", "*4: Vibrato", "*5: Tone Portamento + Volume Slide", "*6: Vibrato + Volume Slide", "*7: Tremolo", "8: Set Panning Position", "*9: Set Sample Offset", "*A: Volume Slide", "*B: Position Jump", "*C: Set Volume", "*D: Pattern Break", "*F: Set Speed (BPM)", "*F: Set Speed (Ticks)", "*E0: Set Filter", "*E1: Fine Slide Up", "*E2: Fine Slide Down", "E3: Glissando Control", "E4: Set Vibrato Waveform", "E5: Set FineTune", "*E6: Set/Jump to Loop", "E7: Set Tremolo Waveform", "E8: Illegal", "*E9: Retrigger Note", "*EA: Fine Volume Slide Up", "*EB: Fine Volume Slide Down", "*EC: Note Cut", "*ED: Note Delay", "*EE: Pattern Delay", "EF: Invert Loop" };
284 static int MOD_FindNote( int period )
286 const int period_table[61] =
289 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960 , 906,
290 856, 808 , 762 , 720 , 678 , 640 , 604 , 570 , 538 , 508 , 480 , 453,
291 428, 404 , 381 , 360 , 339 , 320 , 302 , 285 , 269 , 254 , 240 , 226,
292 214, 202 , 190 , 180 , 170 , 160 , 151 , 143 , 135 , 127 , 120 , 113,
293 107, 101 , 95 , 90 , 85 , 80 , 75 , 71 , 67 , 63 , 60 , 56
296 int closest = 1000000000;
300 for( i = 0; i < 61; ++i )
302 d = abs( period_table[i] - period );
312 printf( "Can't find note with period:%d...\n", period );
318 #define FOUR_CHAR_CODE( ch0, ch1, ch2, ch3 ) \
319 ( (long)(unsigned char)(ch0) | ( (long)(unsigned char)(ch1) << 8 ) | \
320 ( (long)(unsigned char)(ch2) << 16 ) | ( (long)(unsigned char)(ch3) << 24 ) )
322 static int MOD_GetNumChans( ULONG file_format )
324 switch( file_format )
326 case FOUR_CHAR_CODE( 'T', 'D', 'Z', '1'):
330 case FOUR_CHAR_CODE( '2', 'C', 'H', 'N'):
331 case FOUR_CHAR_CODE( 'T', 'D', 'Z', '2'):
335 case FOUR_CHAR_CODE( 'T', 'D', 'Z', '3'):
339 case FOUR_CHAR_CODE( 'M', '.', 'K', '.'):
340 case FOUR_CHAR_CODE( 'F', 'L', 'T', '4'):
341 case FOUR_CHAR_CODE( 'M', '!', 'K', '!'):
345 case FOUR_CHAR_CODE( '5', 'C', 'H', 'N'):
349 case FOUR_CHAR_CODE( '6', 'C', 'H', 'N'):
353 case FOUR_CHAR_CODE( '7', 'C', 'H', 'N'):
357 case FOUR_CHAR_CODE( '8', 'C', 'H', 'N'):
358 case FOUR_CHAR_CODE( 'O', 'C', 'T', 'A'):
359 case FOUR_CHAR_CODE( 'C', 'D', '8', '1'):
363 case FOUR_CHAR_CODE( 'F', 'L', 'T', '8'):
364 return -2; /* Unsupported MOD type */
367 case FOUR_CHAR_CODE( '9', 'C', 'H', 'N'):
371 case FOUR_CHAR_CODE( '1', '0', 'C', 'H'):
375 case FOUR_CHAR_CODE( '1', '1', 'C', 'H'):
379 case FOUR_CHAR_CODE( '1', '2', 'C', 'H'):
383 case FOUR_CHAR_CODE( '1', '3', 'C', 'H'):
387 case FOUR_CHAR_CODE( '1', '4', 'C', 'H'):
391 case FOUR_CHAR_CODE( '1', '5', 'C', 'H'):
395 case FOUR_CHAR_CODE( '1', '6', 'C', 'H'):
399 case FOUR_CHAR_CODE( '1', '7', 'C', 'H'):
400 case FOUR_CHAR_CODE( '1', '8', 'C', 'H'):
401 case FOUR_CHAR_CODE( '1', '9', 'C', 'H'):
402 case FOUR_CHAR_CODE( '2', '0', 'C', 'H'):
403 case FOUR_CHAR_CODE( '2', '1', 'C', 'H'):
404 case FOUR_CHAR_CODE( '2', '2', 'C', 'H'):
405 case FOUR_CHAR_CODE( '2', '3', 'C', 'H'):
406 case FOUR_CHAR_CODE( '2', '4', 'C', 'H'):
407 case FOUR_CHAR_CODE( '2', '5', 'C', 'H'):
408 case FOUR_CHAR_CODE( '2', '6', 'C', 'H'):
409 case FOUR_CHAR_CODE( '2', '7', 'C', 'H'):
410 case FOUR_CHAR_CODE( '2', '8', 'C', 'H'):
411 case FOUR_CHAR_CODE( '2', '9', 'C', 'H'):
412 case FOUR_CHAR_CODE( '3', '0', 'C', 'H'):
413 case FOUR_CHAR_CODE( '3', '1', 'C', 'H'):
414 case FOUR_CHAR_CODE( '3', '2', 'C', 'H'):
415 case FOUR_CHAR_CODE( '3', '3', 'C', 'H'):
416 case FOUR_CHAR_CODE( '3', '4', 'C', 'H'):
417 case FOUR_CHAR_CODE( '3', '5', 'C', 'H'):
418 case FOUR_CHAR_CODE( '3', '6', 'C', 'H'):
419 case FOUR_CHAR_CODE( '3', '7', 'C', 'H'):
420 case FOUR_CHAR_CODE( '3', '8', 'C', 'H'):
421 case FOUR_CHAR_CODE( '3', '9', 'C', 'H'):
422 case FOUR_CHAR_CODE( '4', '0', 'C', 'H'):
423 case FOUR_CHAR_CODE( '4', '1', 'C', 'H'):
424 case FOUR_CHAR_CODE( '4', '2', 'C', 'H'):
425 case FOUR_CHAR_CODE( '4', '3', 'C', 'H'):
426 case FOUR_CHAR_CODE( '4', '4', 'C', 'H'):
427 case FOUR_CHAR_CODE( '4', '5', 'C', 'H'):
428 case FOUR_CHAR_CODE( '4', '6', 'C', 'H'):
429 case FOUR_CHAR_CODE( '4', '7', 'C', 'H'):
430 case FOUR_CHAR_CODE( '4', '8', 'C', 'H'):
431 case FOUR_CHAR_CODE( '4', '9', 'C', 'H'):
432 case FOUR_CHAR_CODE( '5', '0', 'C', 'H'):
433 case FOUR_CHAR_CODE( '5', '1', 'C', 'H'):
434 case FOUR_CHAR_CODE( '5', '2', 'C', 'H'):
435 case FOUR_CHAR_CODE( '5', '3', 'C', 'H'):
436 case FOUR_CHAR_CODE( '5', '4', 'C', 'H'):
437 case FOUR_CHAR_CODE( '5', '5', 'C', 'H'):
438 case FOUR_CHAR_CODE( '5', '6', 'C', 'H'):
439 case FOUR_CHAR_CODE( '5', '7', 'C', 'H'):
440 case FOUR_CHAR_CODE( '5', '8', 'C', 'H'):
441 case FOUR_CHAR_CODE( '5', '9', 'C', 'H'):
442 case FOUR_CHAR_CODE( '6', '0', 'C', 'H'):
443 case FOUR_CHAR_CODE( '6', '1', 'C', 'H'):
444 case FOUR_CHAR_CODE( '6', '2', 'C', 'H'):
445 case FOUR_CHAR_CODE( '6', '3', 'C', 'H'):
446 case FOUR_CHAR_CODE( '6', '4', 'C', 'H'):
447 return -3; /* Too many channels */
451 return -1; /* Unrecognised MOD type */
455 /* 'FLT4', 'FLT8': Startrekker 4/8 channel file. ('FLT6' doesn't exist) */
456 /* 'CD81' : Falcon 8 channel MODs */
457 /* '2CHN' : FastTracker 2 Channel MODs */
458 /* 'yyCH' where yy can be 10, 12, .. 30, 32: FastTracker yy Channel MODs */
459 /* 'yyCH' where yy can be 11, 13, 15: TakeTracker 11, 13, 15 channel MODs */
460 /* 'TDZx' where x can be 1, 2 or 3: TakeTracker 1, 2, 3 channel MODs */
461 /* ModPlug Tracker saves 33-64 channel MODs as '33CH' to '64CH' */
464 static void MOD_ConvMod( FILE* out_file, DATAPACK* samples, DATAPACK* patterns, const char* filename, int mod_num )
468 mod_num_chans[mod_num] = 0;
470 in_file = fopen( filename, "rb" );
473 struct ModSampleTemp samps_temp[32];
475 int i, tmp, line, chan;
476 UBYTE song_length, last_pattern;
477 UBYTE song_data[128];
481 ULONG notes_temp[16][64];
482 int effect_count[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
486 UBYTE song_restart_pos;
488 /*printf( "\nMOD_ConvMod( %s ): Reading...\n", filename ); */
490 fread( temp, 20, 1, in_file ); /* mod name */
492 for( i = 1; i <= 31; ++i )
494 fread( temp, 22, 1, in_file ); /* sample name */
496 fread( &tmp_uword, 2, 1, in_file ); /* sample length */
497 samps_temp[i].length = SwapUWORD( tmp_uword );
499 fread( &tmp_ubyte, 1, 1, in_file ); /* finetune */
500 /*if ( tmp_ubyte & 8 ) */
501 /* tmp_ubyte -= 8; */
503 /* tmp_ubyte += 8; */
504 samps_temp[i].finetune = tmp_ubyte;
505 if ( tmp_ubyte > 15 )
506 printf( "MOD_ConvMod( %s ): Error: finetune > 15...\n", filename );
508 fread( &tmp_ubyte, 1, 1, in_file ); /* volume */
509 samps_temp[i].volume = tmp_ubyte;
511 if ( tmp_ubyte > 64 )
513 printf( "Failed! Reason: Sample vol > 64\n" );
517 fread( &tmp_uword, 2, 1, in_file );
518 samps_temp[i].repeat = SwapUWORD( tmp_uword );
520 fread( &tmp_uword, 2, 1, in_file );
521 tmp = SwapUWORD( tmp_uword );
523 /*samps_temp[i].truelen = samps_temp[i].length; */
527 samps_temp[i].repeat = 65535;
528 samps_temp[i].truelen = samps_temp[i].length;
532 samps_temp[i].truelen = Min( samps_temp[i].repeat + tmp, samps_temp[i].length );
535 /*printf( "i:%d len:%d vol:%d rep:%d fine:%d\n", i, samps_temp[i].truelen, samps_temp[i].volume, samps_temp[i].repeat, samps_temp[i].finetune ); */
538 fread( &song_length, 1, 1, in_file );
539 fread( &song_restart_pos, 1, 1, in_file );
541 if ( (song_length < 1) || (song_length > 128) )
542 printf( "MOD_ConvMod( %s ): song_length:%d\n", filename, song_length );
545 for( i = 0; i <= 127; ++i )
547 fread( &tmp_ubyte, 1, 1, in_file );
548 song_data[i] = tmp_ubyte;
549 if ( tmp_ubyte > last_pattern )
550 last_pattern = tmp_ubyte;
553 if ( last_pattern > 63 )
554 printf( "MOD_ConvMod( %s ): last_pattern:%d\n", filename, last_pattern );
556 fread( &new_temp, 4, 1, in_file );
557 num_chans = MOD_GetNumChans( new_temp );
558 if ( num_chans <= 0 )
562 case -2: /* Unsupported MOD type */
563 printf( "Failed! Reason: Unsupported MOD type (%x)\n", new_temp );
566 case -3: /* Too many channels */
567 printf( "Failed! Reason: Too many channels\n" );
570 default: /* Unrecognised MOD type */
571 printf( "Failed! Reason: Unrecognised MOD type (%x)\n", new_temp );
578 if ( num_chans == 1 )
579 printf( "%d channel...", num_chans );
581 printf( "%d channels...", num_chans );
583 mod_num_chans[mod_num] = num_chans;
586 for( i = 0; i <= last_pattern; ++i )
588 /*curr_note = ¬es_temp[0][0]; */
589 for( line = 0; line < 64; ++line )
591 for( chan = 0; chan < num_chans; ++chan )
593 UBYTE byte1, byte2, byte3, byte4;
594 int samp_num, period, effect;
596 fread( &byte1, 1, 1, in_file );
597 fread( &byte2, 1, 1, in_file );
598 fread( &byte3, 1, 1, in_file );
599 fread( &byte4, 1, 1, in_file );
601 samp_num = (byte1&0xf0)+(byte3>>4);
602 period = (((int)(byte1&0xf))<<8) + ((int)byte2);
603 effect = (((int)(byte3&0xf))<<8) + byte4;
606 if ( (effect>>8) == 0xe )
607 ++effect_count[((effect&0xf0)>>4)+16];
610 if ( (effect>>8) == 0xf )
612 if ( (effect&0xff) > 31 )
619 if ( (effect>>8) == 0xc )
620 if ( (effect&0xff) > 64 )
622 if ( (effect>>8) == 0xd ) /* pattern break */
623 effect = (effect&0xf00) + (((effect>>4)&0xf)*10)+(effect&0xf);
624 ++effect_count[effect>>8];
628 notes_temp[chan][line] = (samp_num<<24) + (MOD_FindNote(period)<<12) + effect;
632 for( chan = 0; chan < num_chans; ++chan )
634 pat[i][chan] = DATA_AppendAligned( patterns, (UBYTE*)(¬es_temp[chan][0]), 256, 256 );
638 for( i = 0; i <= 127; ++i )
640 if ( i >= song_length )
642 for( chan = 0; chan < num_chans; ++chan )
643 patts[mod_num][i][chan] = -1;
647 for( chan = 0; chan < num_chans; ++chan )
648 patts[mod_num][i][chan] = pat[song_data[i]][chan];
652 if ( song_length > max_song_length )
653 max_song_length = song_length;
655 if ( song_restart_pos < 127 )
657 if ( patts[mod_num][song_restart_pos][0] == -1 )
658 song_restart_pos = 0;
662 song_restart_pos = 0;
665 mod_song_restart_pos[mod_num] = song_restart_pos;
667 for( i = 1; i <= 31; ++i )
669 if ( samps_temp[i].length > 0 )
671 MOD_LoadSound( &samps[mod_num][i-1], in_file, samples, samps_temp[i].length, samps_temp[i].truelen, samps_temp[i].repeat );
672 samps[mod_num][i-1].volume = samps_temp[i].volume;
673 samps[mod_num][i-1].finetune = samps_temp[i].finetune;
674 samps[mod_num][i-1].repeat = samps_temp[i].repeat;
681 for( i = 0; i <= 31; ++i )
682 if ( effect_count[i] > 0 )
683 if ( *(effect_name[i]) != '*' )
687 printf( "Unsupported effects:\n" );
690 printf( "%s (%d)\n", effect_name[i], effect_count[i] );
693 printf( "song_length:%d last_pattern:%d\n\n", song_length, last_pattern );
699 printf( "MOD_ConvMod( %s ): Unable to open file for reading...\n", filename );
703 static void MOD_WriteSamples( FILE* out_file, int num_mods )
707 fprintf( out_file, "\n.ALIGN\n.GLOBAL AAS_ModSamples\nAAS_ModSamples:" );
709 for( i = 0; i < num_mods; ++i )
711 fprintf( out_file, "\n.word" );
712 for( s = 0; s < 31; ++s )
715 fprintf( out_file, " %u, %u, %u", samps[i][s].data, (samps[i][s].length<<16)+samps[i][s].repeat, ((samps[i][s].volume&0xff)<<8)+(samps[i][s].finetune&0xff) );
717 fprintf( out_file, ", %u, %u, %u", samps[i][s].data, (samps[i][s].length<<16)+samps[i][s].repeat, ((samps[i][s].volume&0xff)<<8)+(samps[i][s].finetune&0xff) );
721 fprintf( out_file, "\n" );
724 static void MOD_WritePatterns( FILE* out_file, int num_mods )
726 int mod_num, pattern_num, channel_num;
729 fprintf( out_file, "\n.ALIGN\n.GLOBAL AAS_Sequence\nAAS_Sequence:" );
731 for( mod_num = 0; mod_num < num_mods; ++mod_num )
733 fprintf( out_file, "\n.short" );
735 for( pattern_num = 0; pattern_num < 128; ++pattern_num )
737 for( channel_num = 0; channel_num < 16; ++channel_num )
742 fprintf( out_file, " %d", patts[mod_num][pattern_num][channel_num] );
746 fprintf( out_file, ", %d", patts[mod_num][pattern_num][channel_num] );
752 fprintf( out_file, "\n" );
755 static void MOD_WriteNumChans( FILE* out_file, int num_mods )
759 fprintf( out_file, "\n.ALIGN\n.GLOBAL AAS_NumChans\nAAS_NumChans:\n.byte" );
761 for( mod_num = 0; mod_num < num_mods; ++mod_num )
764 fprintf( out_file, ", %d", mod_num_chans[mod_num] );
766 fprintf( out_file, " %d", mod_num_chans[mod_num] );
769 fprintf( out_file, "\n" );
772 static void MOD_WriteSongRestartPos( FILE* out_file, int num_mods )
776 fprintf( out_file, "\n.ALIGN\n.GLOBAL AAS_RestartPos\nAAS_RestartPos:\n.byte" );
778 for( mod_num = 0; mod_num < num_mods; ++mod_num )
781 fprintf( out_file, ", %d", mod_song_restart_pos[mod_num] );
783 fprintf( out_file, " %d", mod_song_restart_pos[mod_num] );
786 fprintf( out_file, "\n" );
790 static void MOD_WritePeriodConvTable( FILE* out_file, int mix_rate )
794 fprintf( out_file, "\nconst UWORD AAS_MOD_period_conv_table[2048] = { 65535" );
796 for( i = 1; i < 2048; ++i )
798 freq = (int)((((double)7093789.2)/((double)(2*i))));
801 fprintf( out_file, ", %d", freq );
804 fprintf( out_file, " };\n" );
808 static int last_samp_length = 0;
810 static int RAW_LoadSound( const char* filename, DATAPACK* sfx )
813 struct stat file_info;
815 if ( stat( filename, &file_info ) == 0 )
819 length = file_info.st_size;
821 in_file = fopen( filename, "rb" );
824 BYTE* samp = (BYTE*)malloc( length+16 );
826 /*printf( "\nRAW_LoadSound( %s ): Reading...\n", filename ); */
828 last_samp_length = length;
830 fread( samp+16, 1, length, in_file );
833 memcpy( samp, samp+length, 16 );
835 MISC_ProcessSound( samp, length+16 );
837 data = DATA_Append( sfx, (UBYTE*)samp, length+16 ) + 16;
841 printf( "Done!\n\n" );
845 printf( "\nRAW_LoadSound( %s ): Unable to open...\n", filename );
850 printf( "\nRAW_LoadSound( %s ): Unable to open...\n", filename );
856 static int WAV_LoadSound( const char* filename, DATAPACK* sfx )
861 last_samp_length = 0;
863 in_file = fopen( filename, "rb" );
868 fread( &tmp, 4, 1, in_file );
870 if ( tmp == 0x46464952 ) /* "RIFF" */
872 fread( &tmp, 4, 1, in_file );
873 fread( &tmp, 4, 1, in_file );
875 if ( tmp == 0x45564157 ) /* "WAVE" */
877 fread( &tmp, 4, 1, in_file );
879 if ( tmp == 0x20746d66 ) /* "fmt " */
881 unsigned short format;
883 fread( &tmp, 4, 1, in_file );
884 fread( &format, 2, 1, in_file );
886 if ( format == 1 ) /* PCM format */
888 unsigned short channels;
890 fread( &channels, 2, 1, in_file );
892 if ( channels == 1 ) /* mono */
894 unsigned short bits_per_sample;
896 fread( &tmp, 4, 1, in_file ); /* sample rate in hz */
897 fread( &tmp, 4, 1, in_file );
898 fread( &tmp, 2, 1, in_file );
899 fread( &bits_per_sample, 2, 1, in_file );
901 if ( bits_per_sample == 8 )
911 ret = fread( &tmp, 4, 1, in_file );
915 if ( tmp == 0x61746164 ) /* "data" */
917 ret = fread( &length, 4, 1, in_file );
935 ret = fread( &size, 4, 1, in_file );
939 fseek( in_file, size, SEEK_CUR );
956 BYTE* samp = (BYTE*)malloc( length+16 );
958 last_samp_length = length;
960 fread( samp+16, 1, length, in_file );
962 memcpy( samp, samp+length, 16 );
964 MISC_ConvSoundToSigned( (UBYTE*)samp, length+16 );
966 MISC_ProcessSound( samp, length+16 );
968 data = DATA_Append( sfx, (UBYTE*)samp, length+16 ) + 16;
972 printf( "Done!\n\n" );
976 printf( "Failed: Unable to find valid data subchunk...\n" );
981 printf( "\nWAV_LoadSound( %s ): Failed: Not 8 bit...\n", filename );
986 printf( "\nWAV_LoadSound( %s ): Failed: Not mono...\n", filename );
991 printf( "\nWAV_LoadSound( %s ): Failed: Not in PCM format...\n", filename );
996 printf( "\nWAV_LoadSound( %s ): Failed: Missing fmt subchunk...\n", filename );
1001 printf( "\nWAV_LoadSound( %s ): Failed: Not a WAVE file...\n", filename );
1006 printf( "\nWAV_LoadSound( %s ): Failed: RIFF header missing...\n", filename );
1013 printf( "\nWAV_LoadSound( %s ): Failed: Unable to open...\n", filename );
1019 __inline static char String_GetChar( const char* txt, int offset )
1021 return *(txt+offset);
1024 static BOOL String_EndsWithMOD( const char* txt )
1026 int txt_len = strlen( txt );
1030 if ( (String_GetChar( txt, txt_len-4 ) == '.') &&
1031 ((String_GetChar( txt, txt_len-3 ) == 'm') || (String_GetChar( txt, txt_len-3 ) == 'M')) &&
1032 ((String_GetChar( txt, txt_len-2 ) == 'o') || (String_GetChar( txt, txt_len-2 ) == 'O')) &&
1033 ((String_GetChar( txt, txt_len-1 ) == 'd') || (String_GetChar( txt, txt_len-1 ) == 'D')) )
1042 static BOOL String_EndsWithRAW( const char* txt )
1044 int txt_len = strlen( txt );
1048 if ( (String_GetChar( txt, txt_len-4 ) == '.') &&
1049 ((String_GetChar( txt, txt_len-3 ) == 'r') || (String_GetChar( txt, txt_len-3 ) == 'R')) &&
1050 ((String_GetChar( txt, txt_len-2 ) == 'a') || (String_GetChar( txt, txt_len-2 ) == 'A')) &&
1051 ((String_GetChar( txt, txt_len-1 ) == 'w') || (String_GetChar( txt, txt_len-1 ) == 'W')) )
1060 static BOOL String_EndsWithWAV( const char* txt )
1062 int txt_len = strlen( txt );
1066 if ( (String_GetChar( txt, txt_len-4 ) == '.') &&
1067 ((String_GetChar( txt, txt_len-3 ) == 'w') || (String_GetChar( txt, txt_len-3 ) == 'W')) &&
1068 ((String_GetChar( txt, txt_len-2 ) == 'a') || (String_GetChar( txt, txt_len-2 ) == 'A')) &&
1069 ((String_GetChar( txt, txt_len-1 ) == 'v') || (String_GetChar( txt, txt_len-1 ) == 'V')) )
1078 static void String_MakeSafe( char* temp )
1082 while( *temp != (char)0 )
1085 if ( !(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9'))) )
1091 static void ShowHelp()
1093 printf( " Usage: Conv2AAS input_dir\n\n" );
1094 printf( " input_dir Directory containing all Protracker\n" );
1095 printf( " MODs & sample data\n\n" );
1096 printf( " Output goes to files AAS_Data.s & AAS_Data.h\n" );
1099 int main( int argc, char *argv[] )
1101 setbuf( stdout, 0 );
1104 printf( "/---------------------------------------------\\\n" );
1105 printf( "| Conv2AAS v1.11 WAV, RAW & MOD -> AAS |\n" );
1106 printf( "| Copyright (c) 2005, Apex Designs |\n" );
1107 printf( "\\---------------------------------------------/\n\n" );
1113 else if ( (argc == 2) && ((strcmp( argv[1], "-help" ) == 0) || (strcmp( argv[1], "-?" ) == 0)) )
1121 out_file_s = fopen( "data/aas_data.s", "w" );
1126 out_file_h = fopen( "data/aas_data.h", "w" );
1131 dir_info = opendir( argv[1] );
1134 int files_converted = 0;
1138 struct dirent* file_info;
1140 samples = DATA_Create( "AAS_SampleData" );
1141 patterns = DATA_Create( "AAS_PatternData" );
1143 fprintf( out_file_h, "#ifndef __AAS_DATA__\n#define __AAS_DATA__\n\n#include \"AAS.h\"\n\n#if AAS_VERSION != 0x111\n#error AAS version does not match Conv2AAS version\n#endif\n\nAAS_BEGIN_DECLS\n" );
1145 fprintf( out_file_s, ".TEXT\n.SECTION .rodata\n.ALIGN\n.ARM\n\n.ALIGN\n.EXTERN AAS_lib_v111\n.GLOBAL AAS_data_v111\nAAS_data_v111:\n.word AAS_lib_v111\n" );
1149 file_info = readdir( dir_info );
1154 strcpy( temp, argv[1] );
1155 strcat( temp, "/" );
1156 strcat( temp, file_info->d_name );
1158 if ( String_EndsWithMOD( file_info->d_name ) )
1161 printf( "Adding MOD %s...", file_info->d_name );
1162 MOD_ConvMod( out_file_h, samples, patterns, temp, mods_found );
1163 /*printf( "Done!\n" ); */
1164 strcpy( temp, file_info->d_name );
1165 *(temp + strlen(temp) - 4) = 0;
1166 String_MakeSafe( temp );
1167 fprintf( out_file_h, "\nextern const AAS_u8 AAS_DATA_MOD_%s;\n", temp );
1168 fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_MOD_%s\nAAS_DATA_MOD_%s:\n.byte %d\n", temp, temp, mods_found );
1171 else if ( String_EndsWithRAW( file_info->d_name ) )
1175 printf( "Adding RAW %s...", file_info->d_name );
1176 val = RAW_LoadSound( temp, samples );
1179 strcpy( temp, file_info->d_name );
1180 *(temp + strlen(temp) - 4) = 0;
1181 String_MakeSafe( temp );
1182 fprintf( out_file_h, "\nextern const AAS_s8* const AAS_DATA_SFX_START_%s;\n", temp );
1183 fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_SFX_START_%s\nAAS_DATA_SFX_START_%s:\n.word AAS_SampleData + %d\n", temp, temp, val );
1184 fprintf( out_file_h, "\nextern const AAS_s8* const AAS_DATA_SFX_END_%s;\n", temp );
1185 fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_SFX_END_%s\nAAS_DATA_SFX_END_%s:\n.word AAS_SampleData + %d\n", temp, temp, val+last_samp_length );
1188 else if ( String_EndsWithWAV( file_info->d_name ) )
1192 printf( "Adding WAV %s...", file_info->d_name );
1193 val = WAV_LoadSound( temp, samples );
1196 strcpy( temp, file_info->d_name );
1197 *(temp + strlen(temp) - 4) = 0;
1198 String_MakeSafe( temp );
1199 fprintf( out_file_h, "\nextern const AAS_s8* const AAS_DATA_SFX_START_%s;\n", temp );
1200 fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_SFX_START_%s\nAAS_DATA_SFX_START_%s:\n.word AAS_SampleData + %d\n", temp, temp, val );
1201 fprintf( out_file_h, "\nextern const AAS_s8* const AAS_DATA_SFX_END_%s;\n", temp );
1202 fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_SFX_END_%s\nAAS_DATA_SFX_END_%s:\n.word AAS_SampleData + %d\n", temp, temp, val+last_samp_length );
1206 } while ( file_info );
1208 closedir( dir_info );
1210 fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_NUM_MODS\nAAS_DATA_NUM_MODS:\n.short %d\n", mods_found );
1212 MOD_WriteSamples( out_file_s, mods_found );
1213 MOD_WritePatterns( out_file_s, mods_found );
1214 MOD_WriteNumChans( out_file_s, mods_found );
1215 MOD_WriteSongRestartPos( out_file_s, mods_found );
1217 /*MOD_WritePeriodConvTable( out_file_h, 24002 ); */
1219 DATA_Write( samples, out_file_s );
1220 DATA_Write( patterns, out_file_s );
1224 fprintf( out_file_h, "\nAAS_END_DECLS\n\n#endif\n" );
1228 printf( "Unable to open directory %s...\n", argv[1] );
1231 fclose( out_file_h );
1235 printf( "Unable to open AASData.h for writing...\n" );
1238 fclose( out_file_s );
1242 printf( "Unable to open AASData.s for writing...\n" );