dropped aas, moved to maxmod
[gbajam21] / tools / mmutil / msl.c
1 /****************************************************************************
2  *                                                          __              *
3  *                ____ ___  ____ __  ______ ___  ____  ____/ /              *
4  *               / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __  /               *
5  *              / / / / / / /_/ />  </ / / / / / /_/ / /_/ /                *
6  *             /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/                 *
7  *                                                                          *
8  *         Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org)         *
9  *                                                                          *
10  * Permission to use, copy, modify, and/or distribute this software for any *
11  * purpose with or without fee is hereby granted, provided that the above   *
12  * copyright notice and this permission notice appear in all copies.        *
13  *                                                                          *
14  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
15  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         *
16  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  *
17  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   *
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    *
19  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  *
20  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           *
21  ****************************************************************************/
22
23 // MAXMOD SOUNDBANK
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #include "errors.h"
30 #include "defs.h"
31 #include "files.h"
32 #include "mas.h"
33 #include "mod.h"
34 #include "s3m.h"
35 #include "xm.h"
36 #include "it.h"
37 #include "wav.h"
38 #include "simple.h"
39 #include "version.h"
40 #include "systems.h"
41 #include "samplefix.h"
42
43 FILE*   F_SCRIPT=NULL;
44
45 FILE*   F_SAMP=NULL;
46 FILE*   F_SONG=NULL;
47
48 FILE*   F_HEADER=NULL;
49
50 u16             MSL_NSAMPS;
51 u16             MSL_NSONGS;
52
53 char    str_msl[256];
54
55 #define TMP_SAMP "sampJ328G54AU3.tmp"
56 #define TMP_SONG "songDJ34957FAI.tmp"
57
58 void MSL_PrintDefinition( char* filename, u16 id, char* prefix );
59
60 #define SAMPLE_HEADER_SIZE (12 + (( target_system == SYSTEM_NDS ) ? 4:0))
61
62 void MSL_Erase( void )
63 {
64         MSL_NSAMPS = 0;
65         MSL_NSONGS = 0;
66         file_delete( TMP_SAMP );
67         file_delete( TMP_SONG );
68 }
69
70 u16 MSL_AddSample( Sample* samp )
71 {
72         u32 sample_length;
73         u32 x;
74         file_open_write_end( TMP_SAMP );
75
76         sample_length = samp->sample_length;
77
78         write32( ((samp->format & SAMPF_16BIT) ? sample_length*2 : sample_length ) + SAMPLE_HEADER_SIZE  +4); // +4 for sample padding
79         write8 ( (target_system == SYSTEM_GBA) ? MAS_TYPE_SAMPLE_GBA : MAS_TYPE_SAMPLE_NDS );
80         write8( MAS_VERSION );
81         write8( samp->filename[0] == '#' ? 1 : 0);
82         write8( BYTESMASHER );
83
84         Write_SampleData(samp);
85
86         file_close_write();
87         MSL_NSAMPS++;
88         return MSL_NSAMPS-1;
89 }
90
91 u16 MSL_AddSampleC( Sample* samp )
92 {
93         u32 st;
94         u32 samp_len;
95         u32 samp_llen;
96         u8 sformat;
97
98         u32 h_filesize;
99         int samp_id;
100         bool samp_match;
101                 
102         int fsize=file_size( TMP_SAMP );
103         if( fsize == 0 )
104         {
105                 return MSL_AddSample( samp );
106         }
107         F_SAMP = fopen( TMP_SAMP, "rb" );
108         fseek( F_SAMP, 0, SEEK_SET );
109         samp_id = 0;
110         while( ftell( F_SAMP ) < fsize )
111         {
112                 h_filesize = read32f( F_SAMP );
113                 read32f( F_SAMP );
114                 samp_len = read32f( F_SAMP );
115                 samp_llen = read32f( F_SAMP );
116                 sformat = read8f( F_SAMP );             /////// BUG! GBA DOESNLT WRITE FORMAT!?
117                 skip8f( 3, F_SAMP );
118                 if( target_system == SYSTEM_NDS )
119                 {
120                         skip8f(4,F_SAMP);
121                 }
122
123                 samp_match=true;
124                 if( samp->sample_length == samp_len && ( samp->loop_type ? samp->loop_end-samp->loop_start : 0xFFFFFFFF ) == samp_llen && sformat == sample_dsformat( samp ) )
125                 {
126                         // verify sample data
127                         if( samp->format & SAMPF_16BIT )
128                         {
129                                 for( st=0; st<samp_len; st++ )
130                                 {
131                                         if( read16f( F_SAMP ) != ((u16*)samp->data)[st] )
132                                         {
133                                                 samp_match = false;
134                                                 break;
135                                         }
136                                 }
137                         }
138                         else
139                         {
140                                 for( st=0; st<samp_len; st++ )
141                                 {
142                                         if( read8f( F_SAMP ) != ((u8*)samp->data)[st] )
143                                         {
144                                                 samp_match = false;
145                                                 break;
146                                         }
147                                 }
148                         }
149                         if( samp_match )
150                         {
151                                 fclose( F_SAMP );
152                                 return samp_id;
153                         }
154                         else
155                         {
156                                 skip8f( (h_filesize-SAMPLE_HEADER_SIZE ) - (st+1)  , F_SAMP );          // +4 to skip padding
157                         }
158                 }
159                 else
160                 {
161                         skip8f( h_filesize- SAMPLE_HEADER_SIZE , F_SAMP ); // +4 to skip padding
162                 }
163                 samp_id++;
164         }
165         fclose( F_SAMP );
166         return MSL_AddSample( samp );
167 }
168
169 u16 MSL_AddModule( MAS_Module* mod )
170 {
171         int x;
172         int samp_id;
173         // ADD SAMPLES
174         for( x = 0; x < mod->samp_count; x++ )
175         {
176                 samp_id = MSL_AddSampleC( &mod->samples[x] );
177                 if( mod->samples[x].filename[0] == '#' )
178                         MSL_PrintDefinition( mod->samples[x].filename+1, (u16)samp_id, "SFX_" );
179                 mod->samples[x].msl_index = samp_id;
180         }
181         
182         file_open_write_end( TMP_SONG );
183         Write_MAS( mod, false, true );
184         file_close_write();
185         MSL_NSONGS++;
186         return MSL_NSONGS-1;
187 }
188
189 void MSL_Export( char* filename )
190 {
191         u32 x;
192         u32 y;
193         u32 file_size;
194
195         u32* parap_samp;
196         u32* parap_song;
197
198         file_open_write( filename );
199         write16( MSL_NSAMPS );
200         write16( MSL_NSONGS );
201         write8( '*' );
202         write8( 'm' );
203         write8( 'a' );
204         write8( 'x' );
205         write8( 'm' );
206         write8( 'o' );
207         write8( 'd' );
208         write8( '*' );
209         
210         parap_samp = (u32*)malloc( MSL_NSAMPS * sizeof( u32 ) );
211         parap_song = (u32*)malloc( MSL_NSONGS * sizeof( u32 ) );
212         
213         // reserve space for parapointers
214         for( x = 0; x < MSL_NSAMPS; x++ )
215                 write32( 0xAAAAAAAA );
216         for( x = 0; x < MSL_NSONGS; x++ )
217                 write32( 0xAAAAAAAA );
218         // copy samples
219         file_open_read( TMP_SAMP );
220         for( x = 0; x < MSL_NSAMPS; x++ )
221         {
222                 align32();
223                 parap_samp[x] = file_tell_write();
224                 file_size = read32();
225                 write32( file_size );
226                 for( y = 0; y < file_size+4; y++ )
227                         write8( read8() );
228         }
229         file_close_read();
230         
231         file_open_read( TMP_SONG );
232         for( x = 0; x < MSL_NSONGS; x++ )
233         {
234                 align32();
235                 parap_song[x] = file_tell_write();
236                 file_size = read32();
237                 write32( file_size );
238                 for( y = 0; y < file_size+4; y++ )
239                         write8( read8() );
240         }
241         file_close_read();
242         
243         file_seek_write( 0x0C, SEEK_SET );
244         for( x = 0; x < MSL_NSAMPS; x++ )
245                 write32( parap_samp[x] );
246         for( x=  0; x < MSL_NSONGS; x++ )
247                 write32( parap_song[x] );
248
249         file_close_write();
250
251         if( parap_samp )
252                 free( parap_samp );
253         if( parap_song )
254                 free( parap_song );
255 }
256
257 void MSL_PrintDefinition( char* filename, u16 id, char* prefix )
258 {
259         char newtitle[64];
260         int x,s=0;
261         if( filename[0] == 0 )  // empty string
262                 return;
263         for( x = 0; x < (int)strlen( filename ); x++ )
264         {
265                 if( filename[x] == '\\' || filename[x] == '/' ) s = x+1; 
266         }
267         for( x = s; x < (int)strlen( filename ); x++ )
268         {
269                 if( filename[x] != '.' )
270                 {
271                         newtitle[x-s] = toupper(filename[x]);
272                         if( newtitle[x-s] >= ' ' && newtitle[x-s] <= '/' )
273                                 newtitle[x-s] = '_';
274                         if( newtitle[x-s] >= ':' && newtitle[x-s] <= '@' )
275                                 newtitle[x-s] = '_';
276                         if( newtitle[x-s] >= '[' && newtitle[x-s] <= '`' )
277                                 newtitle[x-s] = '_';
278                         if( newtitle[x-s] >= '{' )
279                                 newtitle[x-s] = '_';
280                 }
281                 else
282                 {
283                         break;
284                 }
285         }
286         newtitle[x-s] = 0;
287         if( F_HEADER )
288         {
289                 fprintf( F_HEADER, "#define %s%s        %i\r\n", prefix, newtitle, id );
290         }
291 }
292
293 void MSL_LoadFile( char* filename, bool verbose )
294 {
295         Sample wav;
296         MAS_Module mod;
297         int f_ext;
298         if( file_open_read( filename ) )
299         {
300                 printf( "Cannot open %s for reading! Skipping.\n", filename );
301                 return;
302         }
303         f_ext = get_ext( filename );
304         switch( f_ext )
305         {
306         case INPUT_TYPE_MOD:
307                 Load_MOD( &mod, verbose );
308                 MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" );
309                 Delete_Module( &mod );
310                 break;
311         case INPUT_TYPE_S3M:
312                 Load_S3M( &mod, verbose );
313                 MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" );
314                 Delete_Module( &mod );
315                 break;
316         case INPUT_TYPE_XM:
317                 Load_XM( &mod, verbose );
318                 MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" );
319                 Delete_Module( &mod );
320                 break;
321         case INPUT_TYPE_IT:
322                 Load_IT( &mod, verbose );
323                 MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" );
324                 Delete_Module( &mod );
325                 break;
326         case INPUT_TYPE_WAV:
327                 Load_WAV( &wav, verbose, true );
328                 wav.filename[0] = '#';  // set SFX flag (for demo)
329                 MSL_PrintDefinition( filename, MSL_AddSample( &wav ), "SFX_" );
330                 free( wav.data );
331                 break;
332         default:
333                 // print error/warning
334                 printf( "Unknown file %s...\n", filename );
335         }
336         file_close_read();
337         
338 }
339
340 int MSL_Create( char* argv[], int argc, char* output, char* header, bool verbose )
341 {
342 //      int str_w=0;
343 //      u8 pmode=0;
344 //      bool comment=false;
345
346         int x;
347
348         MSL_Erase();
349         str_msl[0] = 0;
350         F_HEADER=NULL;
351         if( header )
352         {
353                 F_HEADER = fopen( header, "wb" );
354         }
355
356 //      if( !F_HEADER )
357 //              return -1;      // needs header file!
358         
359         file_open_write( TMP_SAMP );
360         file_close_write();
361         file_open_write( TMP_SONG );
362         file_close_write();
363         
364         for( x = 1; x < argc; x++ )
365         {
366                 if( argv[x][0] == '-' )
367                 {
368                         
369                 }
370                 else
371                 {
372                         MSL_LoadFile( argv[x], verbose );
373                 }
374         }
375
376         MSL_Export( output );
377
378         if( F_HEADER )
379         {
380                 fprintf( F_HEADER, "#define MSL_NSONGS  %i\r\n", MSL_NSONGS );
381                 fprintf( F_HEADER, "#define MSL_NSAMPS  %i\r\n", MSL_NSAMPS );
382                 fprintf( F_HEADER, "#define MSL_BANKSIZE        %i\r\n", (MSL_NSAMPS+MSL_NSONGS) );
383                 fclose( F_HEADER );
384                 F_HEADER=NULL;
385         }
386
387         file_delete( TMP_SAMP );
388         file_delete( TMP_SONG );
389         return ERR_NONE;
390 }