wonky sweep
[gbajam21] / tools / mmutil / mas.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 #define MAS_C
24
25 #include <stdlib.h>
26 #include "defs.h"
27 #include "files.h"
28 #include "mas.h"
29 #include "simple.h"
30 #include "systems.h"
31 #include "version.h"
32
33 u32 MAS_OFFSET;
34 u32 MAS_FILESIZE;
35
36 static int CalcEnvelopeSize( Instrument_Envelope* env )
37 {
38         return (env->node_count*4) + 8;
39 }
40
41 static int CalcInstrumentSize( Instrument* instr )
42 {
43         int size;
44         size = 12;
45         if( instr->env_flags & 1 )      // volume envelope exists
46                 size += CalcEnvelopeSize( &instr->envelope_volume );
47         if( instr->env_flags & 2 )      // panning envelope exists
48                 size += CalcEnvelopeSize( &instr->envelope_pan );
49         if( instr->env_flags & 4 )      // pitch envelope exists
50                 size += CalcEnvelopeSize( &instr->envelope_pitch );
51         return size;
52 }
53
54 void Write_Instrument_Envelope( Instrument_Envelope* env )
55 {
56         int x;
57         write8( (u8)(env->node_count*4 + 8) ); // maximum is 6+75
58         write8( env->loop_start );
59         write8( env->loop_end );
60         write8( env->sus_start );
61         write8( env->sus_end );
62         write8( env->node_count );
63         write8( env->env_filter );
64         write8( BYTESMASHER );
65         if( env->node_count > 1 )
66         {
67                 int delta;
68                 int base;
69                 int range;
70                 for( x = 0; x < env->node_count; x++ )
71                 {
72                         base = env->node_y[x];
73                         if( x != env->node_count-1 )
74                         {
75                                 
76                                 range = env->node_x[x+1] - env->node_x[x];
77                                 if( range > 511 ) range = 511;
78                                 if( range < 1 ) range = 1;
79                                 delta = (((env->node_y[x+1] - base) * 512) + (range/2)) / range;
80                                 if( delta > 32767 ) delta = 32767;
81                                 if( delta < -32768 ) delta = -32768;
82                                 while( (base+ ((delta*range)>>9)) > 64 ) delta--;
83                                 while( (base+ ((delta*range)>>9)) < 0 ) delta++;
84                         }
85                         else
86                         {
87                                 range = 0;
88                                 delta=0;
89                         }
90                         write16( (u16)delta );
91                         write16( (u16)(base | (range<<7)) );
92                 }
93         }
94 }
95
96 void Write_Instrument( Instrument* inst )
97 {
98         int y;
99         int full_notemap;
100         int first_notemap_samp;
101         align32();
102         inst->parapointer = file_tell_write()-MAS_OFFSET;
103         /*write8( inst->global_volume );
104         write8( (u8)inst->fadeout );
105         write8( inst->random_volume );
106         write8( inst->nna );
107         write8( inst->dct );
108         write8( inst->dca );
109         write8( inst->env_flags );
110         write8( inst->setpan );*/
111
112         write8( inst->global_volume );
113         write8( (u8)inst->fadeout );
114         write8( inst->random_volume );
115         write8( inst->dct );
116         write8( inst->nna );
117         write8( inst->env_flags );
118         write8( inst->setpan );
119         write8( inst->dca );
120
121         full_notemap = 0;
122         first_notemap_samp = (inst->notemap[0] >> 8);
123         for( y = 0; y < 120; y++ )
124         {
125                 if( ((inst->notemap[y] & 0xFF) != y) ||
126                         ((inst->notemap[y] >> 8) != first_notemap_samp) )
127                 {
128                         full_notemap = 1;
129                         break;
130                 }
131         }
132         
133         if( full_notemap )
134         {
135                 // full notemap
136                 // write offset here
137                 write16( (u16)CalcInstrumentSize( inst ) );
138         }
139         else
140         {
141                 // single notemap entry
142                 write16( (u16)(0x8000 | first_notemap_samp) );
143         }
144
145         write16( 0 );   // reserved space
146         
147         if( inst->env_flags & 1 )       // write volume envelope
148                 Write_Instrument_Envelope( &inst->envelope_volume );
149         if( inst->env_flags & 2 )       // write panning envelope
150                 Write_Instrument_Envelope( &inst->envelope_pan );
151         if( inst->env_flags & 4 )       // write pitch envelope
152                 Write_Instrument_Envelope( &inst->envelope_pitch );
153
154         if( full_notemap )
155         {
156                 for( y = 0; y < 120; y++ )
157                         write16( inst->notemap[y] );    
158         }
159 }
160
161 void Write_SampleData( Sample* samp )
162 {
163         u32 x;
164         u32 sample_length = samp->sample_length;
165         u32 sample_looplen = samp->loop_end - samp->loop_start;
166
167         if( target_system == SYSTEM_GBA )
168         {
169                 write32( sample_length );
170                 write32( samp->loop_type ? sample_looplen : 0xFFFFFFFF );
171                 write8( SAMP_FORMAT_U8 );
172                 write8( BYTESMASHER );
173                 write16( (u16) ((samp->frequency * 1024 + (15768/2)) / 15768) );
174         //      write32( 0);
175         }
176         else
177         {
178                 if( samp->format & SAMPF_16BIT )
179                 {
180                         if( samp->loop_type )
181                         {
182                                 write32( samp->loop_start / 2 );
183                                 write32( (samp->loop_end-samp->loop_start) / 2 );
184                         }
185                         else
186                         {
187                                 write32( 0 );
188                                 write32( sample_length/2 );
189                         }
190                 }
191                 else
192                 {
193                         if( samp->loop_type )
194                         {
195                                 write32( samp->loop_start / 4 );
196                                 write32( (samp->loop_end-samp->loop_start) / 4 );
197                         }
198                         else
199                         {
200                                 write32( 0 );
201                                 write32( sample_length/4 );
202                         }
203                 }
204                 write8( sample_dsformat( samp ) );
205                 write8( sample_dsreptype( samp ) );
206                 write16( (u16) ((samp->frequency * 1024 + (32768/2)) / 32768) );
207                 write32( 0);
208         }
209         
210         // write sample data
211         if( samp->format & SAMPF_16BIT )
212         {
213                 for( x = 0; x < sample_length; x++ )
214                         write16( ((u16*)samp->data)[x] );
215
216                 // add padding data
217                 if( samp->loop_type )
218                 {
219                         write16( ((u16*)samp->data)[samp->loop_start] );
220                         write16( ((u16*)samp->data)[samp->loop_start+1] );
221                 }
222                 else
223                 {
224                         write16( 0 );
225                         write16( 0 );
226                 }
227         }
228         else
229         {
230                 for( x = 0; x < sample_length; x++ )
231                         write8( ((u8*)samp->data)[x] );
232
233                 // add padding data
234                 if( samp->loop_type )
235                 {
236                         write8( ((u8*)samp->data)[samp->loop_start] );
237                         write8( ((u8*)samp->data)[samp->loop_start+1] );
238                         write8( ((u8*)samp->data)[samp->loop_start+2] );
239                         write8( ((u8*)samp->data)[samp->loop_start+3] );
240                 }
241                 else
242                 {
243                         for ( x = 0; x < 4; x++ )
244                                 write8( (target_system == SYSTEM_GBA) ? 128 : 0 );
245                 }
246         }
247 }
248
249 void Write_Sample( Sample* samp )
250 {
251         align32(); // align data by 32 bits
252         samp->parapointer = file_tell_write()-MAS_OFFSET;
253
254         write8( samp->default_volume );
255         write8( samp->default_panning );
256         write16( (u16)(samp->frequency/4) );
257         write8( samp->vibtype );
258         write8( samp->vibdepth );
259         write8( samp->vibspeed );
260         write8( samp->global_volume );
261         write16( samp->vibrate );
262         
263         write16( samp->msl_index );
264         
265         if( samp->msl_index == 0xFFFF )
266                 Write_SampleData(samp);
267 }
268
269 void Write_Pattern( Pattern* patt, bool xm_vol )
270 {
271         int row;
272         int col;
273         
274         u16 last_mask[MAX_CHANNELS];
275         u16 last_note[MAX_CHANNELS];
276         u16 last_inst[MAX_CHANNELS];
277         u16 last_vol[MAX_CHANNELS];
278         u16 last_fx[MAX_CHANNELS];
279         u16 last_param[MAX_CHANNELS];
280         
281         u8 chanvar;
282         u8 maskvar;
283
284         u8 emptyvol;
285         
286         PatternEntry* pe;
287         
288         patt->parapointer = file_tell_write()-MAS_OFFSET;
289         write8( (u8)(patt->nrows-1) );
290         
291         patt->cmarks[0] = true;
292         emptyvol = xm_vol ? 0 : 255;
293         
294         // using IT pattern compression
295         
296         for( row = 0; row < patt->nrows; row++ )
297         {
298                 if( patt->cmarks[row] )
299                 {
300                         for( col=0;col<MAX_CHANNELS;col++ )
301                         {
302                                 last_mask[col] = 256; // row is marked, clear previous data
303                                 last_note[col] = 256;
304                                 last_inst[col] = 256;
305                                 last_vol[col]= 256;
306                                 last_fx[col] = 256;
307                                 last_param[col] = 256;
308                         }
309                 }
310                 for( col = 0; col < MAX_CHANNELS; col++ )
311                 {
312                         pe = &patt->data[row*MAX_CHANNELS+col];
313                         if( ((pe->note != 250) || (pe->inst != 0) || (pe->vol != emptyvol) || (pe->fx != 0) || (pe->param != 0)) )
314                         {
315                                 maskvar = 0;
316                                 chanvar = col+1;
317                                 if( pe->note != 250 )
318                                         maskvar |= 1|16;
319                                 
320                                 if( pe->inst != 0 )
321                                         maskvar |= 2|32;
322
323                                 if( pe->note > 250 )    // noteoff/cut disabled start+reset
324                                         maskvar &= ~(16|32);
325                                 
326                                 if( pe->vol != emptyvol )
327                                         maskvar |= 4|64;
328                                 
329                                 if( pe->fx != 0 || pe->param != 0 )
330                                         maskvar |= 8|128;
331                                 
332                                 if( maskvar & 1 )
333                                 {
334                                         if( pe->note == last_note[col] )
335                                         {
336                                                 maskvar &= ~1;
337                                         }
338                                         else
339                                         {
340                                                 last_note[col] = pe->note;
341                                                 if( last_note[col] == 254 || last_note[col] == 255 )            // DONT LET NOTEOFF/NOTECUT USE PREVIOUS PARAMETERS!
342                                                         last_note[col] = 256;
343                                         }
344                                 }
345                                 
346                                 if( maskvar & 2 )
347                                 {
348                                         if( pe->inst == last_inst[col] )
349                                         {
350                                                 maskvar &= ~2;
351                                         }
352                                         else
353                                         {
354                                                 last_inst[col] = pe->inst;
355                                         }
356                                 }
357                                 
358                                 if( maskvar & 4 )
359                                 {
360                                         if( pe->vol == last_vol[col] )
361                                         {
362                                                 maskvar &= ~4;
363                                         }
364                                         else
365                                         {
366                                                 last_vol[col] = pe->vol;
367                                         }
368                                 }
369                                 
370                                 if( maskvar & 8 )
371                                 {
372                                         if( (pe->fx == last_fx[col]) && (pe->param == last_param[col]) )
373                                         {
374                                                 maskvar &= ~8;
375                                         }
376                                         else
377                                         {
378                                                 last_fx[col] = pe->fx;
379                                                 last_param[col] = pe->param;
380                                         }
381                                 }
382                                 
383                                 if( maskvar != last_mask[col] )
384                                 {
385                                         chanvar |= 128;
386                                         last_mask[col] = maskvar;
387                                 }
388
389                                 write8( chanvar );
390                                 if( chanvar & 128 )
391                                         write8( maskvar );
392                                 if( maskvar & 1 )
393                                         write8( pe->note );
394                                 if( maskvar & 2 )
395                                         write8( pe->inst );
396                                 if( maskvar & 4 )
397                                         write8( pe->vol );
398                                 if( maskvar & 8 )
399                                 {
400                                         write8( pe->fx );
401                                         write8( pe->param );
402                                 }
403                         }
404                         else
405                         {
406                                 continue;
407                         }
408                 }
409                 write8( 0 );
410         }
411         
412 }
413
414 void Mark_Pattern_Row( MAS_Module* mod, int order, int row )
415 {
416         Pattern* p;
417         
418         if( row >= 256 )
419                 return;
420         if( mod->orders[order] == 255 )
421                 order = 0;
422         while( mod->orders[order] >= 254 )
423         {
424                 if( mod->orders[order] == 255 )
425                         return;
426                 if( mod->orders[order] == 254 )
427                         order++;
428         }
429         p = &(mod->patterns[mod->orders[order]]);
430         p->cmarks[row] = true;
431 }
432
433 void Mark_Patterns( MAS_Module* mod )
434 {
435         
436         int o;
437         int p;
438         int row;
439         int col;
440         
441         PatternEntry* pe;
442         
443         for( o = 0; o < mod->order_count; o++ )
444         {
445                 p = mod->orders[o];
446                 if( p == 255 )
447                         break;
448                 if( p == 254 )
449                         continue;
450                 if( p >= mod->patt_count )
451                         continue;
452                 for( row = 0; row < mod->patterns[p].nrows; row++ )
453                 {
454                         for( col = 0; col < MAX_CHANNELS; col++ )
455                         {
456                                 pe = &(mod->patterns[p].data[row*MAX_CHANNELS+col]);
457                                 if( pe->fx == 3 )       // PATTERN BREAK
458                                 {
459                                         if( pe->param != 0 ) // if param != 0 then mark next pattern
460                                         {
461                                                 Mark_Pattern_Row( mod, o+1, pe->param );
462                                         }
463                                 }
464                                 else if( pe->fx == 19 )
465                                 {
466                                         if( pe->param == 0xB0 )
467                                         {
468                                                 Mark_Pattern_Row( mod, o, row );
469                                         }
470                                 }
471                         }
472                 }
473         }
474 }
475
476 int Write_MAS( MAS_Module* mod, bool verbose, bool msl_dep )
477 {
478         // SEE MAS_FORM.TXT
479         int x; //,y;
480         int fpos_pointer;
481 //      u8 rsamp=0;
482 //      u16 rsamps[200];
483 //      bool unique=false;
484
485         file_get_byte_count();
486
487         write32( BYTESMASHER );
488         write8( MAS_TYPE_SONG );
489         write8( MAS_VERSION );
490         write8( BYTESMASHER );
491         write8( BYTESMASHER );
492         
493         MAS_OFFSET = file_tell_write();
494
495         write8( (u8)mod->order_count );
496         write8( mod->inst_count );
497         write8( mod->samp_count );
498         write8( mod->patt_count );
499         write8( (u8)((mod->link_gxx ? 1 : 0) | (mod->old_effects ? 2 : 0) | (mod->freq_mode ? 4 : 0) | (mod->xm_mode ? 8 : 0) | (msl_dep ? 16 : 0) | (mod->old_mode ? 32 : 0)) );
500         write8( mod->global_volume );
501         write8( mod->initial_speed );
502         write8( mod->initial_tempo );
503         write8( mod->restart_pos );
504         
505 /*      for( x = 0; x < mod->samp_count; x++ )
506         {
507                 unique=true;
508                 for( y = x-1; y >= 0; y-- )
509                 {
510                         if( mod->samples[x].msl_index == mod->samples[y].msl_index )
511                         {
512                                 mod->samples[x].rsamp_index = mod->samples[y].rsamp_index;
513                                 unique=false;
514                                 break;
515                         }
516                 }
517                 if( unique )
518                 {
519                         rsamps[rsamp]=mod->samples[x].msl_index;
520                         mod->samples[x].rsamp_index = rsamp;
521                         rsamp++;
522                 }
523         }
524         write8( rsamp );*/
525         write8( BYTESMASHER );
526         write8( BYTESMASHER );write8( BYTESMASHER );
527         for( x = 0; x < MAX_CHANNELS; x++ )
528                 write8( mod->channel_volume[x] );
529         for( x = 0; x < MAX_CHANNELS; x++ )
530                 write8( mod->channel_panning[x] );
531         for( x = 0; x < mod->order_count; x++ )
532         {
533                 if( mod->orders[x] < 254 )
534                 {
535                         if( mod->orders[x] < mod->patt_count )
536                                 write8( mod->orders[x] );
537                         else
538                                 write8( 254 );
539                 }
540                 else
541                 {
542                         write8( mod->orders[x] );
543                 }
544         }
545         for( ; x < 200; x++ )
546                 write8( 255 );
547         // reserve space for offsets
548         fpos_pointer = file_tell_write();
549         for( x = 0; x < mod->inst_count*4+mod->samp_count*4+mod->patt_count*4; x++ )
550                 write8( BYTESMASHER ); // BA BA BLACK SHEEP
551 /*      if( msl_dep && target_system == SYSTEM_NDS )
552         {
553                 for( x = 0; x < rsamp; x++ )    // write sample indeces
554                         write16( rsamps[x] );
555         }*/
556         // WRITE INSTRUMENTS
557
558         if( verbose )
559                 printf("Header: %i bytes\n", file_get_byte_count() );
560
561         for( x = 0; x < mod->inst_count; x++ )
562                 Write_Instrument( &mod->instruments[x] );
563
564         
565
566         for( x = 0; x < mod->samp_count; x++ )
567                 Write_Sample( &mod->samples[x] );
568
569         if( verbose )
570                 printf("Instruments: %i bytes\n", file_get_byte_count() );
571         
572         Mark_Patterns( mod );
573         for( x = 0; x < mod->patt_count; x++ )
574         {
575 //              for( y = 0; y < mod->order_count; y++ )
576 //              {
577 //                      if( mod->orders[y] == x )
578                                 Write_Pattern( &mod->patterns[x], mod->xm_mode );
579 //              }
580         }
581         align32();
582
583         if( verbose )
584                 printf("Patterns: %i bytes\n", file_get_byte_count() );
585         MAS_FILESIZE = file_tell_write() - MAS_OFFSET;
586         file_seek_write( MAS_OFFSET-8, SEEK_SET );
587         write32( MAS_FILESIZE );
588         file_seek_write( fpos_pointer, SEEK_SET );
589         for( x = 0; x < mod->inst_count; x++ )
590                 write32( mod->instruments[x].parapointer );
591         for( x = 0; x < mod->samp_count; x++ )
592         {
593                 printf("sample %s is at %d/%d of %d\n", mod->samples[x].name, mod->samples[x].parapointer,
594                         file_tell_write(), mod->samples[x].sample_length);
595                 write32( mod->samples[x].parapointer );
596         }
597         for( x = 0; x < mod->patt_count; x++ )
598                 write32( mod->patterns[x].parapointer );
599         return MAS_FILESIZE;    
600 }
601
602 void Delete_Module( MAS_Module* mod )
603 {
604         int x;
605         if( mod->instruments )
606                 free( mod->instruments );
607         if( mod->samples )
608         {
609                 for( x = 0; x < mod->samp_count; x++ )
610                 {
611                         if( mod->samples[x].data )
612                                 free( mod->samples[x].data );
613                 }
614                 free( mod->samples );
615         }
616         if( mod->patterns )
617         {
618                 free( mod->patterns );
619         }
620 }