├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.am ├── NEWS ├── README ├── autogen.sh ├── configure.ac └── source ├── adpcm.c ├── adpcm.h ├── arm7_st.inc ├── arm9_st.inc ├── defs.h ├── deftypes.h ├── errors.h ├── files.c ├── files.h ├── gba.c ├── gba.h ├── it.c ├── it.h ├── kiwi.c ├── main.c ├── mas.c ├── mas.h ├── mod.c ├── mod.h ├── msl.c ├── msl.h ├── nds.c ├── nds.h ├── poopen.h ├── s3m.c ├── s3m.h ├── samplefix.c ├── samplefix.h ├── simple.c ├── simple.h ├── solution.h ├── systems.h ├── upload.c ├── version.h ├── wav.c ├── wav.h ├── xm.c └── xm.h /.gitignore: -------------------------------------------------------------------------------- 1 | COPYING 2 | INSTALL 3 | Makefile.in 4 | aclocal.m4 5 | autom4te.cache 6 | compile 7 | config.guess 8 | config.sub 9 | configure 10 | depcomp 11 | install-sh 12 | missing 13 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devkitPro/mmutil/8b0792e45852b58fda4def4d263e246d3a73662d/AUTHORS -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Maxmod Utility 2 | 3 | Copyright (c) 2008, Mukunda Johnson 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 11 | * Neither the name of the owners nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 14 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 15 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 16 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 21 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 22 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devkitPro/mmutil/8b0792e45852b58fda4def4d263e246d3a73662d/ChangeLog -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Makefile.am -- Process this file with automake to produce Makefile.in 2 | bin_PROGRAMS = mmutil 3 | 4 | mmutil_SOURCES = source/adpcm.c source/adpcm.h source/defs.h source/deftypes.h \ 5 | source/errors.h source/files.c source/files.h source/gba.c source/gba.h \ 6 | source/it.c source/it.h source/kiwi.c source/main.c source/mas.c source/mas.h \ 7 | source/mod.c source/mod.h source/msl.c source/msl.h source/nds.c source/nds.h \ 8 | source/poopen.h source/s3m.c source/s3m.h source/samplefix.c source/samplefix.h \ 9 | source/simple.c source/simple.h source/solution.h source/systems.h source/upload.c \ 10 | source/version.h source/wav.c source/wav.h source/xm.c source/xm.h \ 11 | source/arm7_st.inc source/arm9_st.inc 12 | 13 | mmutil_LDADD = -lm 14 | 15 | mmutil_CPPFLAGS = -Wno-multichar 16 | 17 | EXTRA_DIST = autogen.sh 18 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devkitPro/mmutil/8b0792e45852b58fda4def4d263e246d3a73662d/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devkitPro/mmutil/8b0792e45852b58fda4def4d263e246d3a73662d/README -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | aclocal 2 | autoconf 3 | automake --add-missing -c 4 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ(2.61) 5 | AC_INIT([mmutil],[1.10.1],[https://github.com/devkitPro/mmutil/issues]) 6 | AC_CONFIG_SRCDIR([source/adpcm.c]) 7 | 8 | AM_INIT_AUTOMAKE([subdir-objects]) 9 | 10 | AC_CANONICAL_BUILD 11 | AC_CANONICAL_HOST 12 | 13 | AC_PROG_CC 14 | AM_PROG_CC_C_O 15 | 16 | AC_CONFIG_FILES([Makefile]) 17 | AC_OUTPUT 18 | -------------------------------------------------------------------------------- /source/adpcm.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 26 | #include "defs.h" 27 | #include "deftypes.h" 28 | #include "mas.h" 29 | 30 | const s8 IndexTable[8] = { 31 | -1, -1, -1, -1, 2, 4, 6, 8 32 | }; 33 | 34 | const u16 AdpcmTable[89] = { 35 | 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 36 | 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 37 | 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 38 | 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 39 | 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 40 | 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 41 | 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 42 | 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 43 | 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 44 | }; 45 | 46 | static int read_sample( Sample* sample, int position ) 47 | { 48 | int s; 49 | if( sample->format & SAMPF_16BIT ) 50 | { 51 | s = ((s16*)sample->data)[position]; 52 | } 53 | else 54 | { 55 | // expand 8-bit value 56 | int a = ((s8*)sample->data)[position]; 57 | s = (a<<8); 58 | } 59 | if( s < -32767 ) s = -32767; // is this necessary?... 60 | return s; 61 | } 62 | 63 | static int minmax( int value, int low, int high ) 64 | { 65 | if( value < low ) value = low; 66 | if( value > high ) value = high; 67 | return value; 68 | } 69 | 70 | static int calc_delta( int diff, int step ) 71 | { 72 | int delta = (step >> 3); // t/8 73 | 74 | if( diff >= step ) { // t/1 75 | diff -= step; 76 | delta += step; 77 | } 78 | if( diff >= (step>>1) ) { // t/2 79 | diff -= step>>1; 80 | delta += step>>1; 81 | } 82 | if( diff >= (step>>2) ) { // t/4 83 | diff -= step>>2; 84 | delta += step>>2; 85 | } 86 | return delta; 87 | } 88 | 89 | //---------------------------------------------------------------------- 90 | // Compresses a sample with IMA-ADPCM 91 | // Make sure the data has proper alignment/length! 92 | //---------------------------------------------------------------------- 93 | void adpcm_compress_sample( Sample* sample ) 94 | //---------------------------------------------------------------------- 95 | { 96 | u32 x; 97 | u8* output; 98 | 99 | int prev_value; 100 | int curr_value; 101 | 102 | int diff; 103 | int data; 104 | int delta; 105 | 106 | int index; 107 | int step; 108 | 109 | // allocate space for sample (compressed size) 110 | output = (u8*)malloc( sample->sample_length/2+4 ); 111 | 112 | prev_value = read_sample( sample, 0 ); 113 | index = 0; 114 | 115 | { // determine best (or close to best) initial table value 116 | 117 | int i; 118 | int smallest_error; 119 | int tmp_error; 120 | smallest_error = 9999999; 121 | 122 | 123 | diff = read_sample( sample, 1 ) - read_sample( sample, 0 ); 124 | 125 | for( i = 0; i < 88; i++ ) 126 | { 127 | tmp_error = calc_delta( diff, i ) - diff; 128 | if( tmp_error < smallest_error ) 129 | { 130 | smallest_error = tmp_error; 131 | index = i; 132 | } 133 | } 134 | } 135 | 136 | // set data header 137 | (*((u32*)output)) = prev_value // initial PCM16 value 138 | | (index << 16); // initial table index value 139 | 140 | step = AdpcmTable[index]; 141 | 142 | for( x = 0; x < sample->sample_length; x++ ) 143 | { 144 | curr_value = read_sample( sample, x ); 145 | 146 | diff = curr_value - prev_value; 147 | if( diff < 0 ) 148 | { 149 | // negate difference & set negative bit 150 | diff = -diff; 151 | data = 8; 152 | } 153 | else 154 | { 155 | // clear negative flag 156 | data = 0; 157 | } 158 | 159 | /* 160 | difference calculation: 161 | Diff = AdpcmTable[Index]/8 162 | IF (data4bit AND 1) THEN Diff = Diff + AdpcmTable[Index]/4 163 | IF (data4bit AND 2) THEN Diff = Diff + AdpcmTable[Index]/2 164 | IF (data4bit AND 4) THEN Diff = Diff + AdpcmTable[Index]/1 165 | */ 166 | 167 | delta = (step >> 3); // t/8 (always) 168 | 169 | if( diff >= step ) { // t/1 170 | data |= 4; 171 | diff -= step; 172 | delta += step; 173 | } 174 | if( diff >= (step>>1) ) { // t/2 175 | data |= 2; 176 | diff -= step>>1; 177 | delta += step>>1; 178 | } 179 | if( diff >= (step>>2) ) { // t/4 180 | data |= 1; 181 | diff -= step>>2; 182 | delta += step>>2; 183 | } 184 | 185 | // add/subtract delta 186 | prev_value += (data&8) ? -delta : delta; 187 | 188 | // claamp output 189 | prev_value = minmax( prev_value, -0x7FFF, 0x7FFF ); 190 | 191 | // add index table value (and clamp) 192 | index = minmax( index + IndexTable[data & 7], 0, 88 ); 193 | 194 | // read new step value 195 | step = AdpcmTable[index]; 196 | 197 | // write output 198 | if( (x & 1) ) 199 | output[(x>>1)+4] |= (data) << 4; 200 | else 201 | output[(x>>1)+4] = (data); 202 | } 203 | 204 | // delete old sample 205 | free( sample->data ); 206 | 207 | // assign new sample 208 | sample->data = output; 209 | 210 | // new format 211 | sample->format = SAMP_FORMAT_ADPCM; 212 | 213 | // new length/loop 214 | sample->sample_length = (sample->sample_length/2) +4; 215 | sample->loop_start /= 2; 216 | sample->loop_end /= 2; 217 | 218 | // step loop past adpcm header 219 | sample->loop_start += 4; 220 | sample->loop_end += 4; 221 | } 222 | -------------------------------------------------------------------------------- /source/adpcm.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> (b) ? (b) : (x))) 35 | 36 | #endif // _defs_h_ 37 | -------------------------------------------------------------------------------- /source/deftypes.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> > 8) ); 182 | file_byte_count += 2; 183 | } 184 | 185 | void write24( u32 p_v ) 186 | { 187 | write8( (u8)(p_v & 0xFF) ); 188 | write8( (u8)((p_v >> 8) & 0xFF) ); 189 | write8( (u8)((p_v >> 16) & 0xFF) ); 190 | file_byte_count += 3; 191 | } 192 | 193 | void write32( u32 p_v ) 194 | { 195 | write16( (u16)(p_v & 0xFFFF) ); 196 | write16( (u16)(p_v >> 16) ); 197 | file_byte_count += 4; 198 | } 199 | 200 | void align16( void ) 201 | { 202 | if( ftell( fout ) & 1 ) 203 | write8( BYTESMASHER ); 204 | } 205 | 206 | void align32( void ) 207 | { 208 | if( ftell( fout ) & 3 ) 209 | write8( BYTESMASHER ); 210 | if( ftell( fout ) & 3 ) 211 | write8( BYTESMASHER ); 212 | if( ftell( fout ) & 3 ) 213 | write8( BYTESMASHER ); 214 | } 215 | 216 | void align32f( FILE* p_file ) 217 | { 218 | if( ftell( p_file ) & 3 ) 219 | write8( BYTESMASHER ); 220 | if( ftell( p_file ) & 3 ) 221 | write8( BYTESMASHER ); 222 | if( ftell( p_file ) & 3 ) 223 | write8( BYTESMASHER ); 224 | } 225 | 226 | void skip8( u32 count ) 227 | { 228 | fseek( fin, count, SEEK_CUR ); 229 | // while( count ) 230 | // { 231 | // //read8(); 232 | // count--; 233 | // } 234 | } 235 | 236 | void skip8f( u32 count, FILE* p_file ) 237 | { 238 | fseek( p_file, count, SEEK_CUR ); 239 | // while( count ) // this was a major slowdown! 240 | // { 241 | // //read8f( p_file ); 242 | // 243 | // count--; 244 | // } 245 | } 246 | 247 | void file_delete( char* filename ) 248 | { 249 | if( file_exists( filename ) ) 250 | remove( filename ); 251 | } 252 | 253 | int file_get_byte_count( ) 254 | { 255 | int a = file_byte_count; 256 | file_byte_count = 0; 257 | return a; 258 | } 259 | -------------------------------------------------------------------------------- /source/files.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 27 | 28 | int file_size( char* filename ); 29 | int file_open_read( char* filename ); 30 | int file_open_write( char* filename ); 31 | int file_open_write_end( char* filename ); 32 | void file_close_read( void ); 33 | void file_close_write( void ); 34 | u8 read8( void ); 35 | u16 read16( void ); 36 | u32 read24( void ); 37 | u32 read32( void ); 38 | void write8( u8 p_v ); 39 | void write16( u16 p_v ); 40 | void write24( u32 p_v ); 41 | void write32( u32 p_v ); 42 | void align16( void ); 43 | void align32( void ); 44 | void skip8( u32 count ); 45 | int file_seek_read( int offset, int mode ); 46 | int file_seek_write( int offset, int mode ); 47 | int file_tell_read( void ); 48 | int file_tell_write( void ); 49 | 50 | u8 read8f( FILE* p_fin ); 51 | u16 read16f( FILE* p_fin ); 52 | u32 read32f( FILE* p_fin ); 53 | void align32f( FILE* p_file ); 54 | void skip8f( u32 count, FILE* p_file ); 55 | 56 | void file_delete( char* filename ); 57 | 58 | bool file_exists( char* filename ); 59 | 60 | int file_get_byte_count(); 61 | 62 | int file_tell_size( void ); 63 | 64 | #define FILE_OPEN_OKAY 0 65 | #define FILE_OPEN_ERROR -1 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /source/gba.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 26 | #include 27 | #include "defs.h" 28 | #include "mas.h" 29 | #include "it.h" 30 | #include "files.h" 31 | #include "simple.h" 32 | #include "errors.h" 33 | #include "samplefix.h" 34 | 35 | #ifdef SUPER_ASCII 36 | #define vstr_it_div "────────────────────────────────────────────\n" 37 | #define vstr_it_instr_top "┌─────┬──────┬─────┬─────┬───────────────────────────┐\n" 38 | #define vstr_it_instr_head "│INDEX│VOLUME│ NNA │ ENV │ NAME │\n" 39 | #define vstr_it_instr_slice "├─────┼──────┼─────┼─────┼───────────────────────────┤\n" 40 | #define vstr_it_instr "│%3i │ %3i%% │ %3s │ %s%s%s │ %-26s│\n" 41 | #define vstr_it_instr_bottom "└─────┴──────┴─────┴─────┴───────────────────────────┘\n" 42 | 43 | #define vstr_it_samp_top "┌─────┬──────┬───────┬──────┬─────────┬───────────────────────────┐\n" 44 | #define vstr_it_samp_head "│INDEX│VOLUME│DVOLUME│ LOOP │ MID-C │ NAME │\n" 45 | #define vstr_it_samp_slice "├─────┼──────┼───────┼──────┼─────────┼───────────────────────────┤\n" 46 | #define vstr_it_samp "│%3i │ %3i%% │ %3i%% │ %4s │%6ihz │ %-26s│\n" 47 | #define vstr_it_samp_bottom "└─────┴──────┴───────┴──────┴─────────┴───────────────────────────┘\n" 48 | 49 | #define vstr_it_pattern " \x0e %2i" 50 | #else 51 | #define vstr_it_div "--------------------------------------------\n" 52 | #define vstr_it_instr_top vstr_it_div 53 | #define vstr_it_instr_head " INDEX VOLUME NNA ENV NAME\n" 54 | //#define vstr_it_instr_slice "" 55 | #define vstr_it_instr " %-3i %3i%% %3s %s%s%s %-26s \n" 56 | #define vstr_it_instr_bottom vstr_it_div 57 | 58 | #define vstr_it_samp_top vstr_it_div 59 | #define vstr_it_samp_head " INDEX VOLUME DVOLUME LOOP MID-C NAME \n" 60 | //#define vstr_it_samp_slice "" 61 | #define vstr_it_samp " %-3i %3i%% %3i%% %4s %6ihz %-26s \n" 62 | #define vstr_it_samp_bottom vstr_it_div 63 | 64 | #define vstr_it_pattern " * %2i" 65 | #endif 66 | 67 | bool Load_IT_Envelope( Instrument_Envelope* env, bool unsign ) 68 | { 69 | // read envelopes 70 | u8 a; 71 | u8 node_count; 72 | int x; 73 | 74 | bool env_loop=false; 75 | bool env_sus=false; 76 | bool env_enabled=false; 77 | bool env_filter=false; 78 | 79 | memset( env, 0, sizeof( Instrument_Envelope ) ); 80 | 81 | a=read8(); 82 | 83 | if( a & 1 ) 84 | env_enabled = true; 85 | if( !(a & 2) ) 86 | { 87 | env->loop_start=255; 88 | env->loop_end =255; 89 | } 90 | else 91 | env_loop=true; 92 | if( !(a & 4) ) 93 | { 94 | env->sus_start=255; 95 | env->sus_end=255; 96 | } 97 | else 98 | env_sus=true; 99 | 100 | if( a & 128 ) 101 | { 102 | unsign=false; 103 | env_filter=true; 104 | env->env_filter=env_filter; 105 | } 106 | 107 | node_count=read8(); 108 | if( node_count != 0 ) 109 | env->env_valid=true; 110 | 111 | env->node_count = node_count; 112 | if( env_loop ) 113 | { 114 | env->loop_start=read8(); 115 | env->loop_end=read8(); 116 | } 117 | else 118 | { 119 | skip8( 2 ); 120 | } 121 | if( env_sus ) 122 | { 123 | env->sus_start=read8(); 124 | env->sus_end=read8(); 125 | } 126 | else 127 | { 128 | skip8( 2 ); 129 | } 130 | for( x = 0; x < 25; x++ ) 131 | { 132 | env->node_y[x] = read8(); 133 | if( unsign ) 134 | env->node_y[x] += 32; 135 | env->node_x[x] = read16(); 136 | 137 | } 138 | read8(); // unused byte 139 | env->env_enabled = env_enabled; 140 | return env_enabled; 141 | } 142 | 143 | int Load_IT_Instrument( Instrument* inst, bool verbose, int index ) 144 | { 145 | u16 a; 146 | int x; 147 | 148 | memset( inst, 0, sizeof( Instrument ) ); 149 | 150 | skip8( 17 ); 151 | inst->nna =read8(); 152 | inst->dct =read8(); 153 | inst->dca =read8(); 154 | a=read16(); if( a > 255 ) a = 255; 155 | inst->fadeout =(u8)a; 156 | skip8( 2 ); 157 | inst->global_volume =read8(); 158 | a= read8(); 159 | a = (a&128) | ((a&127)*2 > 127 ? 127 : (a&127)*2); 160 | inst->setpan =a^128; 161 | inst->random_volume =read8(); 162 | skip8( 5 ); 163 | for( x = 0; x < 26; x++ ) 164 | inst->name[x] = read8(); 165 | skip8( 6 ); 166 | 167 | for( x = 0; x < 120; x++ ) 168 | inst->notemap[x] = read16(); 169 | 170 | inst->env_flags=0; 171 | 172 | Load_IT_Envelope( &inst->envelope_volume, false ); 173 | inst->env_flags |= inst->envelope_volume.env_valid ? 1 : 0; 174 | inst->env_flags |= inst->envelope_volume.env_enabled ? 8 : 0; 175 | 176 | Load_IT_Envelope( &inst->envelope_pan, true ); 177 | inst->env_flags |= inst->envelope_pan.env_enabled ? 2 : 0; 178 | 179 | Load_IT_Envelope( &inst->envelope_pitch, true ); 180 | inst->env_flags |= inst->envelope_pitch.env_enabled ? 4 : 0; 181 | 182 | if( verbose ) 183 | { 184 | printf( vstr_it_instr, \ 185 | index+1, \ 186 | (inst->global_volume*100)/128, \ 187 | ((inst->nna==0)?"CUT":((inst->nna==1)?"CON":((inst->nna==2)?"OFF":((inst->nna==3)?"FAD":"???")))), \ 188 | (inst->env_flags&8)?"V":"-", \ 189 | (inst->env_flags&2)?"P":"-", \ 190 | (inst->env_flags&4)?"T":"-", \ 191 | inst->name ); 192 | 193 | /* printf( "%i%% ", (inst->global_volume*100) / 128 ); 194 | switch( inst->nna ) 195 | { 196 | case 0: 197 | printf( "%s ", "CUT" ); break; 198 | case 1: 199 | printf( "%s ", "OFF" ); break; 200 | case 2: 201 | printf( "%s ", "CONT" ); break; 202 | case 3: 203 | printf( "%s ", "FADE" ); break; 204 | } 205 | if( (!(inst->env_flags & 2)) && (!(inst->env_flags & 4)) && (!(inst->env_flags & 8)) ) 206 | { 207 | printf( "- " ); 208 | } 209 | else 210 | { 211 | if( inst->env_flags & 8) 212 | printf( "V" ); 213 | if( inst->env_flags & 2) 214 | printf( "P" ); 215 | if( inst->env_flags & 4) 216 | printf( "S" ); 217 | printf( " " ); 218 | } 219 | printf( "%s\n", inst->name );*/ 220 | } 221 | 222 | skip8( 7 ); 223 | return 0; 224 | } 225 | 226 | void Create_IT_Instrument( Instrument* inst, int sample ) 227 | { 228 | int x; 229 | 230 | memset( inst, 0, sizeof( Instrument ) ); 231 | 232 | inst->global_volume =128; 233 | 234 | for( x = 0; x < 120; x++ ) 235 | inst->notemap[x] = x+sample*256; 236 | } 237 | 238 | int Load_IT_Sample( Sample* samp ) 239 | { 240 | bool bit16; 241 | bool hasloop; 242 | bool pingpong; 243 | bool samp_unsigned=false; 244 | u8 a; 245 | u32 samp_length; 246 | u32 loop_start; 247 | u32 loop_end; 248 | u32 c5spd; 249 | u32 data_address; 250 | int x; 251 | 252 | memset( samp, 0, sizeof( Sample ) ); 253 | samp->msl_index = 0xFFFF; 254 | 255 | if( read32() != 'SPMI' ) 256 | return ERR_UNKNOWNSAMPLE; 257 | for( x = 0; x < 12; x++ ) // dos filename 258 | samp->filename[x] = read8(); 259 | if( read8() != 0 ) 260 | return ERR_UNKNOWNSAMPLE; 261 | samp->global_volume = read8(); 262 | a = read8(); 263 | samp->it_compression = a & 8 ? 1 : 0; 264 | bit16 = a & 2; 265 | hasloop = a & 16; 266 | pingpong = a & 64; 267 | samp->default_volume = read8(); 268 | for( x = 0; x < 26; x++ ) 269 | samp->name[x] = read8(); 270 | a=read8(); 271 | samp->default_panning = read8(); 272 | samp->default_panning = (((samp->default_panning&127) == 64) ? 127 : (samp->default_panning<<1)) | (samp->default_panning&128); 273 | if( !(a & 1) ) 274 | samp_unsigned=true; 275 | samp_length = read32(); 276 | loop_start=read32(); 277 | loop_end=read32(); 278 | c5spd=read32(); 279 | 280 | samp->frequency = c5spd; 281 | samp->sample_length = samp_length; 282 | samp->loop_start = loop_start; 283 | samp->loop_end = loop_end; 284 | 285 | skip8( 8 ); // susloop start/end 286 | data_address = read32(); 287 | samp->vibspeed = read8(); 288 | samp->vibdepth = read8(); 289 | samp->vibrate = read8(); 290 | samp->vibtype = read8(); 291 | samp->datapointer = data_address; 292 | if( hasloop ) 293 | { 294 | if( pingpong ) 295 | samp->loop_type = 2; 296 | else 297 | samp->loop_type = 1; 298 | samp->loop_start = loop_start; 299 | samp->loop_end = loop_end; 300 | } 301 | else 302 | { 303 | samp->loop_type = 0; 304 | } 305 | samp->format = (bit16 ? SAMPF_16BIT : 0) | (samp_unsigned ? 0 : SAMPF_SIGNED ); 306 | if( samp->sample_length == 0 ) samp->loop_type = 0; 307 | return 0; 308 | } 309 | 310 | int Load_IT_Sample_CMP( u8 *p_dest_buffer, int samp_len, u16 cmwt, bool bit16 ); 311 | int Load_IT_SampleData( Sample* samp, u16 cwmt ) 312 | { 313 | u32 x; 314 | int a; 315 | if( samp->sample_length == 0 ) return 0; 316 | if( samp->format & SAMPF_16BIT ) 317 | samp->data = (u16*)malloc( (u32)(samp->sample_length)*2 ); 318 | else 319 | samp->data = (u8*)malloc( (u32)(samp->sample_length) ); 320 | 321 | if( !samp->it_compression ) 322 | { 323 | 324 | for( x = 0; x < samp->sample_length; x++ ) 325 | { 326 | if( samp->format & SAMPF_16BIT ) 327 | { 328 | if( !(samp->format & SAMPF_SIGNED) ) 329 | { 330 | a = (unsigned short)read16(); 331 | } 332 | else 333 | { 334 | a = (signed short)read16(); 335 | a += 32768; 336 | } 337 | ((u16*)samp->data)[x] = (u16)a; 338 | } 339 | else 340 | { 341 | if( !(samp->format & SAMPF_SIGNED) ) 342 | { 343 | a = (unsigned char)read8(); 344 | } 345 | else 346 | { 347 | a = (signed char)read8(); 348 | a += 128; 349 | } 350 | ((u8*)samp->data)[x] = (u8)a; 351 | } 352 | 353 | } 354 | } 355 | else 356 | { 357 | Load_IT_Sample_CMP( samp->data, samp->sample_length, cwmt, (bool)(samp->format & SAMPF_16BIT) ); 358 | } 359 | FixSample( samp ); 360 | return 0; 361 | } 362 | 363 | int Empty_IT_Pattern( Pattern *patt ) { 364 | 365 | int x; 366 | memset( patt, 0, sizeof( Pattern ) ); 367 | patt->nrows = 64; 368 | for( x = 0; x < patt->nrows*MAX_CHANNELS; x++ ) { 369 | patt->data[x].note = 250; // special clears for vol¬e 370 | patt->data[x].vol = 255; 371 | } 372 | return ERR_NONE; 373 | } 374 | 375 | int Load_IT_Pattern( Pattern* patt ) 376 | { 377 | int x; 378 | int clength; 379 | u8 chanvar; 380 | u8 chan; 381 | u8 maskvar; 382 | 383 | u8 old_maskvar[MAX_CHANNELS]; 384 | u8 old_note[MAX_CHANNELS]; 385 | u8 old_inst[MAX_CHANNELS]; 386 | u8 old_vol[MAX_CHANNELS]; 387 | u8 old_fx[MAX_CHANNELS]; 388 | u8 old_param[MAX_CHANNELS]; 389 | 390 | memset( patt, 0, sizeof( Pattern ) ); 391 | 392 | clength = read16(); 393 | patt->nrows = read16(); 394 | skip8(4); 395 | 396 | patt->clength = clength; 397 | 398 | for( x = 0; x < patt->nrows*MAX_CHANNELS; x++ ) 399 | { 400 | patt->data[x].note = 250; // special clears for vol¬e 401 | patt->data[x].vol = 255; 402 | } 403 | 404 | 405 | // DECOMPRESS IT PATTERN 406 | 407 | for( x = 0; x < patt->nrows; x++ ) 408 | { 409 | GetNextChannelMarker: 410 | chanvar = read8(); // Read byte into channelvariable. 411 | if( chanvar == 0 ) // if(channelvariable = 0) then end of row 412 | continue; 413 | 414 | chan = (chanvar-1) & 63; // Channel = (channelvariable-1) & 63 415 | if( chan >= MAX_CHANNELS ) 416 | return ERR_MANYCHANNELS; 417 | 418 | if( chanvar & 128 ) // if(channelvariable & 128) then read byte into maskvariable 419 | old_maskvar[chan] = read8(); 420 | 421 | maskvar = old_maskvar[chan]; 422 | 423 | if( maskvar & 1 ) // if(maskvariable & 1), then read note. (byte value) 424 | { 425 | old_note[chan] = read8(); 426 | patt->data[x*MAX_CHANNELS+chan].note = old_note[chan]; 427 | } 428 | 429 | if( maskvar & 2 ) // if(maskvariable & 2), then read instrument (byte value) 430 | { 431 | old_inst[chan] = read8(); 432 | patt->data[x*MAX_CHANNELS+chan].inst = old_inst[chan]; 433 | } 434 | 435 | if( maskvar & 4 ) // if(maskvariable & 4), then read volume/panning (byte value) 436 | { 437 | old_vol[chan] = read8(); 438 | patt->data[x*MAX_CHANNELS+chan].vol = old_vol[chan]; 439 | } 440 | 441 | if( maskvar & 8 ) // if(maskvariable & 8), then read command (byte value) and commandvalue 442 | { 443 | old_fx[chan] = read8(); 444 | patt->data[x*MAX_CHANNELS+chan].fx = old_fx[chan]; 445 | old_param[chan] = read8(); 446 | patt->data[x*MAX_CHANNELS+chan].param = old_param[chan]; 447 | } 448 | 449 | if( maskvar & 16 ) // if(maskvariable & 16), then note = lastnote for channel 450 | patt->data[x*MAX_CHANNELS+chan].note = old_note[chan]; 451 | if( maskvar & 32 ) // if(maskvariable & 32), then instrument = lastinstrument for channel 452 | patt->data[x*MAX_CHANNELS+chan].inst = old_inst[chan]; 453 | if( maskvar & 64 ) // if(maskvariable & 64), then volume/pan = lastvolume/pan for channel 454 | patt->data[x*MAX_CHANNELS+chan].vol = old_vol[chan]; 455 | if( maskvar & 128 ) // if(maskvariable & 128), then { 456 | { 457 | patt->data[x*MAX_CHANNELS+chan].fx = old_fx[chan]; // command = lastcommand for channel and 458 | patt->data[x*MAX_CHANNELS+chan].param = old_param[chan];// commandvalue = lastcommandvalue for channel 459 | } 460 | goto GetNextChannelMarker; 461 | } 462 | 463 | return ERR_NONE; 464 | } 465 | 466 | int Load_IT( MAS_Module* itm, bool verbose ) 467 | { 468 | u8 b; 469 | u16 w; 470 | int x; 471 | int cc; 472 | 473 | u16 cwt; 474 | u16 cmwt; 475 | 476 | u32* parap_inst; 477 | u32* parap_samp; 478 | u32* parap_patt; 479 | 480 | bool instr_mode; 481 | 482 | memset( itm, 0, sizeof( MAS_Module ) ); 483 | 484 | if( read32() != 'MPMI' ) 485 | return ERR_INVALID_MODULE; 486 | for( x = 0; x < 28; x++ ) 487 | itm->title[x] = read8(); 488 | itm->order_count = (u16)read16(); 489 | itm->inst_count = (u8)read16(); 490 | itm->samp_count = (u8)read16(); 491 | itm->patt_count = (u8)read16(); 492 | cwt = read16(); 493 | cmwt = read16(); // upward compatible 494 | //skip8( 4 ); // created with tracker / upward compatible 495 | w = read16(); // flags 496 | itm->stereo = w & 1; 497 | itm->inst_mode = instr_mode = w & 4; 498 | itm->freq_mode = w & 8; 499 | itm->old_effects = w & 16; 500 | itm->link_gxx = w & 32; 501 | skip8( 2 ); // special 502 | itm->global_volume = read8(); 503 | skip8( 1 ); // mix volume 504 | itm->initial_speed = read8(); 505 | itm->initial_tempo = read8(); 506 | 507 | if( verbose ) 508 | { 509 | printf( vstr_it_div ); 510 | printf( "Loading IT, \"%s\"\n", itm->title ); 511 | printf( vstr_it_div ); 512 | printf( "#Orders......%i\n", itm->order_count ); 513 | printf( "#Instr.......%i\n", itm->inst_count ); 514 | printf( "#Samples.....%i\n", itm->samp_count ); 515 | printf( "#Patterns....%i\n", itm->patt_count ); 516 | printf( "Stereo.......%s\n", itm->stereo ? "Yes" : "No" ); 517 | printf( "Slides.......%s\n", itm->freq_mode ? "Linear" : "Amiga" ); 518 | printf( "Old Effects..%s\n", itm->old_effects ? "Yes" : "No" ); 519 | printf( "Global Vol...%i%%\n", (itm->global_volume*100)/128 ); 520 | printf( "Speed........%i\n", itm->initial_speed ); 521 | printf( "Tempo........%i\n", itm->initial_tempo ); 522 | printf( "Instruments..%s\n", instr_mode ? "Yes" : "Will be supplied" ); 523 | printf( vstr_it_div ); 524 | } 525 | skip8( 12 ); // SEP, PWD, MSGLENGTH, MESSAGE OFFSET, [RESERVED] 526 | for( x = 0; x < 64; x++ ) 527 | { 528 | b = read8(); 529 | if( x < MAX_CHANNELS ) 530 | itm->channel_panning[x] = b*4 > 255 ? 255 : b*4; // map 0->64 to 0->255 531 | } 532 | for( x = 0; x < 64; x++ ) 533 | { 534 | b = read8(); 535 | if( x < MAX_CHANNELS ) 536 | itm->channel_volume[x] = b; 537 | } 538 | for( x = 0; x < itm->order_count; x++ ) 539 | itm->orders[x] = read8(); 540 | 541 | parap_inst = (u32*)malloc( itm->inst_count * sizeof( u32 ) ); 542 | parap_samp = (u32*)malloc( itm->samp_count * sizeof( u32 ) ); 543 | parap_patt = (u32*)malloc( itm->patt_count * sizeof( u32 ) ); 544 | 545 | for( x = 0; x < itm->inst_count; x++ ) 546 | parap_inst[x] = read32(); 547 | for( x = 0; x < itm->samp_count; x++ ) 548 | parap_samp[x] = read32(); 549 | for( x = 0; x < itm->patt_count; x++ ) 550 | parap_patt[x] = read32(); 551 | 552 | itm->samples = (Sample*)malloc( itm->samp_count * sizeof( Sample ) ); 553 | itm->patterns = (Pattern*)malloc( itm->patt_count * sizeof( Pattern ) ); 554 | 555 | if( instr_mode ) 556 | { 557 | itm->instruments = (Instrument*)malloc( itm->inst_count * sizeof( Instrument ) ); 558 | if( verbose ) 559 | { 560 | printf( "Loading Instruments...\n" ); 561 | printf( vstr_it_instr_top ); 562 | printf( vstr_it_instr_head ); 563 | #ifdef vstr_it_instr_slice 564 | printf( vstr_it_instr_slice ); 565 | #endif 566 | //printf( "INDEX VOLUME NNA ENV NAME\n" ); 567 | } 568 | 569 | // read instruments 570 | for( x = 0; x < itm->inst_count; x++ ) 571 | { 572 | // if( verbose ) 573 | // printf( "%i ", x+1 ); 574 | file_seek_read( parap_inst[x], SEEK_SET ); 575 | Load_IT_Instrument( &itm->instruments[x], verbose, x ); 576 | } 577 | 578 | if( verbose ) 579 | { 580 | printf( vstr_it_instr_bottom ); 581 | } 582 | } 583 | 584 | if( verbose ) 585 | { 586 | printf( "Loading Samples...\n" ); 587 | printf( vstr_it_samp_top ); 588 | printf( vstr_it_samp_head ); 589 | #ifdef vstr_it_samp_slice 590 | printf( vstr_it_samp_slice ); 591 | #endif 592 | //printf( "INDEX VOLUME DVOLUME LOOP MID-C NAME\n" ); 593 | } 594 | 595 | // read samples 596 | for( x = 0; x < itm->samp_count; x++ ) 597 | { 598 | file_seek_read( parap_samp[x], SEEK_SET ); 599 | Load_IT_Sample( &itm->samples[x] ); 600 | if( verbose ) 601 | { 602 | printf( vstr_it_samp, x+1, (itm->samples[x].global_volume * 100) / 64, (itm->samples[x].default_volume * 100) / 64, itm->samples[x].loop_type == 0 ? "None" : (itm->samples[x].loop_type == 1 ? "Forw" : "BIDI"), itm->samples[x].frequency, itm->samples[x].name ); 603 | //printf( "%i %i%% %i%% %s %ihz %s\n", x+1, (itm->samples[x].global_volume*100) / 64, (itm->samples[x].default_volume*100) / 64, itm->samples[x].loop_type == 0 ? "None" : (itm->samples[x].loop_type == 1 ? "Yes" : "BIDI"), itm->samples[x].frequency, itm->samples[x].name ); 604 | } 605 | } 606 | 607 | if( verbose ) 608 | { 609 | printf( vstr_it_samp_bottom ); 610 | } 611 | 612 | if( !instr_mode ) 613 | { 614 | if( verbose ) 615 | { 616 | printf( "Adding Instrument Templates...\n" ); 617 | printf( vstr_it_div ); 618 | } 619 | itm->inst_count = itm->samp_count; 620 | itm->instruments = (Instrument*)malloc( itm->inst_count * sizeof( Instrument ) ); 621 | cc=0; 622 | for( x = 0; x < itm->samp_count; x++ ) 623 | { 624 | if( verbose ) 625 | { 626 | printf( " * %2i", x+1 ); 627 | cc++; 628 | if( cc == 15) 629 | { 630 | cc=0; 631 | printf("\n"); 632 | } 633 | } 634 | Create_IT_Instrument( &itm->instruments[x], x+1 ); 635 | } 636 | if( verbose ) 637 | { 638 | if( cc != 0 ) 639 | printf( (((x+1)%15)==0)?"":"\n" ); 640 | printf( vstr_it_div ); 641 | } 642 | } 643 | 644 | if(verbose) 645 | { 646 | printf( "Reading Patterns...\n" ); 647 | printf( vstr_it_div ); 648 | } 649 | 650 | // read patterns 651 | cc=0; 652 | for( x = 0; x < itm->patt_count; x++ ) 653 | { 654 | file_seek_read( parap_patt[x], SEEK_SET ); 655 | if( parap_patt[x] != 0 ) 656 | { 657 | if( verbose ) 658 | { 659 | printf( vstr_it_pattern, x+1 ); 660 | cc++; 661 | if( cc == 15 ) 662 | { 663 | cc=0; 664 | printf("\n"); 665 | } 666 | } 667 | Load_IT_Pattern( &itm->patterns[x] ); 668 | 669 | } 670 | else 671 | { 672 | Empty_IT_Pattern( &itm->patterns[x] ); 673 | //memset( &itm->patterns[x], 0, sizeof( Pattern ) ); 674 | } 675 | } 676 | 677 | 678 | if( verbose ) 679 | { 680 | if( cc != 0 ) 681 | printf( "\n" ); 682 | printf( vstr_it_div ); 683 | printf( "Loading Sample Data...\n" ); 684 | } 685 | // read sample data 686 | for( x = 0; x < itm->samp_count; x++ ) 687 | { 688 | file_seek_read( itm->samples[x].datapointer, SEEK_SET ); 689 | Load_IT_SampleData( &itm->samples[x], cmwt ); 690 | } 691 | 692 | if( verbose ) 693 | { 694 | printf( vstr_it_div ); 695 | } 696 | 697 | free( parap_inst ); 698 | free( parap_samp ); 699 | free( parap_patt ); 700 | 701 | return ERR_NONE; 702 | } 703 | 704 | /* * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE 705 | 706 | -The following sample decompression code is based on CHIBITRACKER's code (http://chibitracker.berlios.de) which is based on xmp's code.(http://xmp.helllabs.org) which is based in openCP code. 707 | 708 | * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE */ 709 | 710 | int Load_IT_CompressedSampleBlock( u8** buffer ) 711 | { 712 | u32 size; 713 | u32 x; 714 | size = read16(); 715 | (*buffer) = (u8*)malloc( size+4 ); 716 | (*buffer)[size+0]=0; 717 | (*buffer)[size+1]=0; 718 | (*buffer)[size+2]=0; 719 | (*buffer)[size+3]=0; 720 | for( x = 0; x < size; x++ ) 721 | (*buffer)[x] = read8(); 722 | return ERR_NONE; 723 | } 724 | 725 | int Load_IT_Sample_CMP( u8 *p_dest_buffer, int samp_len, u16 cmwt, bool bit16 ) 726 | { 727 | u8* c_buffer=NULL; 728 | u16 block_length; // length of compressed data block in samples 729 | u16 block_position; // position in block 730 | u8 bit_width; // actual "bit width" 731 | u32 aux_value; // value read from file to be processed 732 | s16 d1, d2; // integrator buffers (d2 for it2.15) 733 | s8 d18, d28; 734 | s8 v8; // sample value 735 | s16 v16; // sample value 16 bit 736 | bool it215; // is this an it215 module? 737 | u16 border; 738 | u8 tmp_shift; 739 | u32 bit_readpos=0; 740 | int i; 741 | 742 | u32 nbits, dsize; 743 | 744 | u8 *dest8_write = (u8 *)p_dest_buffer; 745 | u16 *dest16_write = (u16 *)p_dest_buffer; 746 | 747 | nbits = bit16 ? 16 : 8; 748 | dsize = bit16 ? 4 : 3; 749 | for (i=0;i read new width; 785 | bit_readpos += dsize; 786 | bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; 787 | // and expand it 788 | continue; // ... next value 789 | } 790 | } 791 | else 792 | { 793 | if ( aux_value == ((u32)1 << ((u32)bit_width - 1)) ) { // check for "100..." 794 | 795 | aux_value = readbits( c_buffer, bit_readpos, dsize )+1; //read_n_bits_from_IT_compressed_block(3) + 1; // yes -> read new width; 796 | bit_readpos += dsize; 797 | bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; 798 | // and expand it 799 | continue; // ... next value 800 | } 801 | } 802 | 803 | } else if ( bit_width < nbits + 1 ) { // method 2 (7-8 bits) 804 | 805 | if( bit16 ) 806 | { 807 | border = (0xFFFF >> ((nbits+1) - bit_width)) - (nbits/2); 808 | // lower border for width chg 809 | 810 | if ( (int)aux_value > (int)border && (int)aux_value <= ((int)border + nbits) ) { 811 | 812 | aux_value -= border; // convert width to 1-8 813 | bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; 814 | // and expand it 815 | continue; // ... next value 816 | } 817 | } 818 | else 819 | { 820 | border = (0xFF >> ((nbits+1) - bit_width)) - (nbits/2); 821 | // lower border for width chg 822 | 823 | if ( aux_value > border && aux_value <= (border + nbits) ) { 824 | 825 | aux_value -= border; // convert width to 1-8 826 | bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; 827 | // and expand it 828 | continue; // ... next value 829 | } 830 | } 831 | 832 | } else if ( bit_width == nbits+1 ) { // method 3 (9 bits) 833 | 834 | if ( aux_value & (1<>=tmp_shift; 855 | } 856 | else 857 | { 858 | v8=(aux_value << tmp_shift); 859 | v8>>=tmp_shift; 860 | } 861 | 862 | } 863 | else 864 | { 865 | if( bit16 ) 866 | v16 = (s16) aux_value; 867 | else 868 | v8 = (s8) aux_value; 869 | } 870 | 871 | if( bit16 ) 872 | { 873 | // integrate upon the sample values 874 | d1 += v16; 875 | d2 += d1; 876 | 877 | // ... and store it into the buffer 878 | *(dest16_write++) = (it215 ? d2+32768 : d1+32768); 879 | } 880 | else 881 | { 882 | // integrate upon the sample values 883 | d18 += v8; 884 | d28 += d18; 885 | 886 | // ... and store it into the buffer 887 | *(dest8_write)++ = (it215 ? (int)d28+128 : (int)d18+128); 888 | } 889 | block_position++; 890 | 891 | } 892 | 893 | // now subtract block lenght from total length and go on 894 | if( c_buffer ) { 895 | free( c_buffer ); c_buffer=NULL; } 896 | samp_len -= block_length; 897 | } 898 | 899 | return ERR_NONE; 900 | } 901 | -------------------------------------------------------------------------------- /source/it.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 25 | #include 26 | #include 27 | 28 | u32 time_start; 29 | 30 | void kiwi_start( void ) 31 | { 32 | int r; 33 | time_start = time(NULL); 34 | srand( time_start ); 35 | r=0; 36 | 37 | rand();rand();rand();rand();rand();rand();rand();rand();rand();rand();rand();rand();rand();rand(); 38 | 39 | switch( r ) 40 | { 41 | case 0: 42 | printf( "Your lucky number today is %i!\n", rand() ); 43 | break; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /source/main.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 27 | #include 28 | #include 29 | #include 30 | 31 | #include "defs.h" 32 | #include "mas.h" 33 | #include "mod.h" 34 | #include "s3m.h" 35 | #include "xm.h" 36 | #include "it.h" 37 | #include "gba.h" 38 | #include "nds.h" 39 | #include "files.h" 40 | #include "errors.h" 41 | #include "simple.h" 42 | #include "msl.h" 43 | #include "systems.h" 44 | #include "wav.h" 45 | #include "samplefix.h" 46 | 47 | extern void kiwi_start(void); 48 | 49 | int target_system; 50 | 51 | bool ignore_sflags; 52 | int PANNING_SEP; 53 | 54 | int number_of_inputs; 55 | 56 | #define USAGE "\n\ 57 | ************************\n\ 58 | * Maxmod Utility "PACKAGE_VERSION" *\n\ 59 | ************************\n\ 60 | \n\ 61 | Usage:\n\ 62 | mmutil [options] input files ...\n\ 63 | \n\ 64 | Input may be MOD, S3M, XM, IT, and/or WAV\n\ 65 | \n\ 66 | .------------.----------------------------------------------------.\n\ 67 | | Option | Description |\n\ 68 | |------------|----------------------------------------------------|\n\ 69 | | -o | Set output file. |\n\ 70 | | -h
| Set header output file. |\n\ 71 | | -m | Output MAS file rather than soundbank. |\n\ 72 | | -d | Use for NDS projects. |\n\ 73 | | -b | Create test ROM. (use -d for .nds, otherwise .gba) |\n\ 74 | | -i | Ignore sample flags. |\n\ 75 | | -v | Enable verbose output. |\n\ 76 | | -p | Set initial panning separation for MOD/S3M. |\n\ 77 | `-----------------------------------------------------------------'\n\ 78 | \n\ 79 | .-----------------------------------------------------------------.\n\ 80 | | Examples: |\n\ 81 | |-----------------------------------------------------------------|\n\ 82 | | Create DS soundbank file (soundbank.bin) from input1.xm |\n\ 83 | | and input2.it Also output header file (soundbank.h) |\n\ 84 | | |\n\ 85 | | mmutil -d input1.xm input2.it -osoundbank.bin -hsoundbank.h |\n\ 86 | |-----------------------------------------------------------------|\n\ 87 | | Create test GBA ROM from two inputs |\n\ 88 | | |\n\ 89 | | mmutil -b input1.mod input2.s3m -oTEST.gba |\n\ 90 | |-----------------------------------------------------------------|\n\ 91 | | Create test NDS ROM from three inputs |\n\ 92 | | |\n\ 93 | | mmutil -d -b input1.xm input2.s3m testsound.wav |\n\ 94 | `-----------------------------------------------------------------'\n\ 95 | www.maxmod.org\n\ 96 | " 97 | 98 | void print_usage( void ) 99 | { 100 | printf( USAGE ); 101 | } 102 | 103 | void print_error( int err ) 104 | { 105 | switch( err ) 106 | { 107 | case ERR_INVALID_MODULE: 108 | printf( "Invalid module!\n" ); 109 | break; 110 | case ERR_MANYARGS: 111 | printf( "Too many arguments!\n" ); 112 | break; 113 | case ERR_NOINPUT: 114 | printf( "No input file!\n" ); 115 | break; 116 | case ERR_NOWRITE: 117 | printf( "Unable to write file!\n" ); 118 | break; 119 | case ERR_BADINPUT: 120 | printf( "Cannot parse input filename!\n" ); 121 | break; 122 | } 123 | } 124 | 125 | int GetYesNo( void ) 126 | { 127 | char c = 0; 128 | c = tolower(getchar()); 129 | while( getchar() != '\n' ); 130 | while( c != 'y' && c != 'n' ) 131 | { 132 | printf( "Was that a yes? " ); 133 | c = tolower(getchar()); 134 | while( getchar() != '\n' ); 135 | } 136 | return c == 'y' ? 1 : 0; 137 | } 138 | 139 | //------------------------------------------------------------------------------------------------ 140 | int main(int argc, char* argv[]) 141 | //------------------------------------------------------------------------------------------------ 142 | { 143 | char* str_input=NULL; 144 | char* str_output=NULL; 145 | char* str_header=NULL; 146 | 147 | MAS_Module mod; 148 | 149 | int strl; 150 | 151 | int input_type=0; 152 | 153 | int strp; 154 | int strpi; 155 | 156 | bool g_flag=false; 157 | bool v_flag=false; 158 | bool m_flag=false; 159 | bool z_flag=false; 160 | int a; 161 | 162 | int output_size; 163 | 164 | ignore_sflags=false; 165 | 166 | number_of_inputs=0; 167 | 168 | PANNING_SEP = 128; 169 | 170 | //------------------------------------------------------------------------ 171 | // parse arguments 172 | //------------------------------------------------------------------------ 173 | 174 | for( a = 1; a < argc; a++ ) 175 | { 176 | if( argv[a][0] == '-' ) 177 | { 178 | if( argv[a][1] == 'b' ) 179 | g_flag = true; 180 | else if( argv[a][1] == 'v' ) 181 | v_flag = true; 182 | else if( argv[a][1] == 'd' ) 183 | target_system = SYSTEM_NDS; 184 | else if( argv[a][1] == 'i' ) 185 | ignore_sflags = true; 186 | else if( argv[a][1] == 'p' ) 187 | PANNING_SEP = ((argv[a][2] - '0') * 256)/9; 188 | else if( argv[a][1] == 'o' ) 189 | str_output = argv[a]+2; 190 | else if( argv[a][1] == 'h' ) 191 | str_header = argv[a]+2; 192 | else if( argv[a][1] == 'm' ) 193 | m_flag = true; 194 | else if( argv[a][1] == 'z' ) 195 | z_flag = true; 196 | } 197 | else if( !str_input ) 198 | { 199 | str_input = argv[a]; 200 | number_of_inputs=1; 201 | } 202 | else 203 | { 204 | number_of_inputs++; 205 | } 206 | } 207 | 208 | if( number_of_inputs==0 ) 209 | { 210 | print_usage(); 211 | return 0; 212 | } 213 | 214 | if( z_flag ) 215 | { 216 | kiwi_start(); 217 | file_open_read( str_input ); 218 | Sample s; 219 | 220 | Load_WAV( &s, false,false ); 221 | 222 | s.name[0] = '%'; 223 | s.name[1] = 'c'; 224 | s.name[2] = 0; 225 | 226 | FixSample( &s ); 227 | 228 | file_close_read(); 229 | file_open_write( str_output ); 230 | 231 | int i; 232 | for( i = 0; i < s.sample_length; i++ ) 233 | write8( ((u8*)s.data)[i] ); 234 | 235 | file_close_write(); 236 | printf("okay\n"); 237 | return 0; 238 | } 239 | 240 | if( m_flag & g_flag ) 241 | { 242 | printf("-m and -g cannot be combined.\n"); 243 | return -1; 244 | } 245 | 246 | if( m_flag && number_of_inputs != 1 ) 247 | { 248 | printf( "-m only supports one input.\n" ); 249 | return -1; 250 | } 251 | 252 | //--------------------------------------------------------------------------- 253 | // m/g generate output target if not given 254 | //--------------------------------------------------------------------------- 255 | 256 | if( m_flag || g_flag) 257 | { 258 | if( !str_output ) 259 | { 260 | if( number_of_inputs == 1 ) 261 | { 262 | if( strlen(str_input) < 4 ) 263 | { 264 | print_error( ERR_BADINPUT ); 265 | return -1; 266 | } 267 | strp = strlen(str_input); 268 | str_output = (char*)malloc( strp+2 ); 269 | strcpy(str_output, str_input); 270 | strp=strlen(str_output)-1; 271 | 272 | for( strpi=strp; str_output[strpi] != '.' && strpi != 0; strpi-- ); 273 | if( strpi == 0 ) 274 | { 275 | print_error( ERR_BADINPUT ); 276 | return -1; 277 | } 278 | 279 | str_output[strpi++] = '.'; 280 | if( !g_flag ) 281 | { 282 | str_output[strpi++] = 'm'; 283 | str_output[strpi++] = 'a'; 284 | str_output[strpi++] = 's'; 285 | str_output[strpi++] = 0; 286 | } 287 | else 288 | { 289 | if( target_system == SYSTEM_GBA ) 290 | { 291 | str_output[strpi++] = 'g'; 292 | str_output[strpi++] = 'b'; 293 | str_output[strpi++] = 'a'; 294 | str_output[strpi++] = 0; 295 | } 296 | else if( target_system == SYSTEM_NDS ) 297 | { 298 | str_output[strpi++] = 'n'; 299 | str_output[strpi++] = 'd'; 300 | str_output[strpi++] = 's'; 301 | str_output[strpi++] = 0; 302 | } 303 | else 304 | { 305 | // error! 306 | } 307 | } 308 | str_output[strpi++] = 0; 309 | } 310 | else 311 | { 312 | printf( "No output file! (-o option)\n" ); 313 | return -1; 314 | } 315 | } 316 | } 317 | 318 | // catch filename too small 319 | strl=strlen(str_input); 320 | if( strl < 4 ) 321 | { 322 | print_error( ERR_BADINPUT ); 323 | return -1; 324 | } 325 | 326 | if( m_flag ) 327 | { 328 | if( file_open_read( str_input ) ) 329 | { 330 | printf( "Cannot open %s for reading!\n", str_input ); 331 | return -1; 332 | } 333 | input_type = get_ext( str_input ); 334 | 335 | switch( input_type ) 336 | { 337 | //------------------------------------------------------ 338 | case INPUT_TYPE_MOD: 339 | //------------------------------------------------------ 340 | if( Load_MOD( &mod, v_flag ) ) 341 | { 342 | print_error( ERR_INVALID_MODULE ); 343 | file_close_read(); 344 | return -1; 345 | } 346 | break; 347 | //------------------------------------------------------ 348 | case INPUT_TYPE_S3M: 349 | //------------------------------------------------------ 350 | if( Load_S3M( &mod, v_flag ) ) 351 | { 352 | print_error( ERR_INVALID_MODULE ); 353 | file_close_read(); 354 | return -1; 355 | } 356 | break; 357 | //------------------------------------------------------ 358 | case INPUT_TYPE_XM: 359 | //------------------------------------------------------ 360 | if( Load_XM( &mod, v_flag ) ) 361 | { 362 | print_error( ERR_INVALID_MODULE ); 363 | file_close_read(); 364 | return -1; 365 | } 366 | break; 367 | //------------------------------------------------------ 368 | case INPUT_TYPE_IT: 369 | //------------------------------------------------------ 370 | if( Load_IT( &mod, v_flag ) ) 371 | { 372 | // ERROR! 373 | print_error( ERR_INVALID_MODULE ); 374 | file_close_read(); 375 | return -1; 376 | } 377 | break; 378 | } 379 | 380 | file_close_read(); 381 | 382 | if( file_exists( str_output ) ) 383 | { 384 | printf( "Output file exists! Overwrite? (y/n) " ); 385 | if( !GetYesNo() ) 386 | { 387 | printf( "Operation Canceled!\n" ); 388 | return -1; 389 | } 390 | 391 | } 392 | 393 | if( file_open_write( str_output ) ) 394 | { 395 | print_error( ERR_NOWRITE ); 396 | return -1; 397 | } 398 | 399 | printf( "Writing .mas............\n" ); 400 | 401 | // output MAS 402 | output_size = Write_MAS( &mod, v_flag, false ); 403 | 404 | 405 | file_close_write(); 406 | 407 | Delete_Module( &mod ); 408 | 409 | if( v_flag ) 410 | { 411 | #ifdef SUPER_ASCII 412 | printf( "Success! \x02 \n" ); 413 | #else 414 | printf( "Success! :) \n" ); 415 | #endif 416 | } 417 | } 418 | else if( g_flag ) 419 | { 420 | int i; 421 | 422 | MSL_Create( argv, argc, "tempSH308GK.bin", 0, v_flag ); 423 | 424 | if( file_exists( str_output ) ) 425 | { 426 | printf( "Output file exists! Overwrite? (y/n) " ); 427 | if( !GetYesNo() ) 428 | { 429 | printf( "Operation Canceled!\n" ); 430 | return -1; 431 | } 432 | 433 | } 434 | 435 | if( file_open_write( str_output ) ) 436 | { 437 | print_error( ERR_NOWRITE ); 438 | return -1; 439 | } 440 | 441 | if( target_system == SYSTEM_GBA ) 442 | { 443 | if( v_flag ) 444 | printf( "Making GBA ROM.......\n" ); 445 | Write_GBA(); 446 | } 447 | else if( target_system == SYSTEM_NDS ) 448 | { 449 | if( v_flag ) 450 | printf( "Making NDS ROM.......\n" ); 451 | Write_NDS(); 452 | } 453 | 454 | output_size = file_size( "tempSH308GK.bin" ); 455 | file_open_read( "tempSH308GK.bin" ); 456 | 457 | if( target_system == SYSTEM_GBA ) 458 | { 459 | write32( (output_size < 248832) ? 1 : 0 ); 460 | } 461 | 462 | for( i = 0; i < output_size; i++ ) 463 | { 464 | write8( read8() ); 465 | } 466 | 467 | file_close_read(); 468 | file_close_write(); 469 | 470 | file_delete( "tempSH308GK.bin" ); 471 | 472 | if( g_flag && target_system == SYSTEM_NDS ) 473 | Validate_NDS( str_output, output_size ); 474 | 475 | if( v_flag ) 476 | { 477 | printf( "Success! :D\n" ); 478 | 479 | if( g_flag && target_system == SYSTEM_GBA ) 480 | { 481 | if( output_size < 262144 ) 482 | { 483 | printf("ROM can be multibooted!!\n" ); 484 | } 485 | } 486 | } 487 | } 488 | else 489 | { 490 | MSL_Create( argv, argc, str_output, str_header, v_flag ); 491 | } 492 | return 0; 493 | } 494 | -------------------------------------------------------------------------------- /source/mas.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 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 && sample_length >= (samp->loop_start + 2) ) 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 && sample_length >= (samp->loop_start + 4) ) 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;coldata[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 | } 621 | -------------------------------------------------------------------------------- /source/mas.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 26 | #include 27 | #include 28 | #include "defs.h" 29 | #include "mas.h" 30 | #include "mod.h" 31 | #include "xm.h" 32 | #include "files.h" 33 | #include "simple.h" 34 | #include "errors.h" 35 | #include "samplefix.h" 36 | 37 | #ifdef SUPER_ASCII 38 | #define vstr_mod_div "────────────────────────────────────────────\n" 39 | #define vstr_mod_samp_top "┌─────┬──────┬─────┬──────┬───────┬───────────────────────┐\n" 40 | #define vstr_mod_samp_header "│INDEX│LENGTH│LOOP │VOLUME│ MID-C │ NAME │\n" 41 | #define vstr_mod_samp_slice "├─────┼──────┼─────┼──────┼───────┼───────────────────────┤\n" 42 | #define vstr_mod_samp "│ %2i │%5i │ %3s │ %3i%% │ %ihz│ %-22s│\n" 43 | #define vstr_mod_samp_bottom "└─────┴──────┴─────┴──────┴───────┴───────────────────────┘\n" 44 | #define vstr_mod_pattern " \x0e %2i%s" 45 | #else 46 | #define vstr_mod_div "--------------------------------------------\n" 47 | #define vstr_mod_samp_top vstr_mod_div 48 | #define vstr_mod_samp_header " INDEX LENGTH LOOP VOLUME MID-C NAME \n" 49 | //#define vstr_mod_samp_slice "" 50 | #define vstr_mod_samp " %-2i %-5i %-3s %3i%% %ihz %-22s \n" 51 | #define vstr_mod_samp_bottom vstr_mod_div 52 | #define vstr_mod_pattern " * %2i%s" 53 | #endif 54 | 55 | #ifdef _MSC_VER 56 | double round( double value ) 57 | { 58 | return floor(value+0.5); 59 | } 60 | #endif 61 | 62 | int Create_MOD_Instrument( Instrument* inst, u8 sample ) 63 | { 64 | int x; 65 | memset( inst, 0, sizeof( Instrument ) ); 66 | inst->global_volume = 128; 67 | // setup notemap 68 | for( x = 0; x < 120; x++ ) 69 | { 70 | inst->notemap[x] = x | ((sample+1)<<8); 71 | } 72 | return ERR_NONE; 73 | } 74 | 75 | int Load_MOD_SampleData( Sample* samp ) 76 | { 77 | u32 t; 78 | if( samp->sample_length > 0 ) 79 | { 80 | samp->data = (u8*)malloc( samp->sample_length ); // allocate a SAMPLE_LENGTH sized pointer to buffer in memory and load the sample into it 81 | for( t = 0; t < samp->sample_length; t++ ) 82 | { 83 | ((u8*)samp->data)[t] = read8() + 128; // unsign data 84 | } 85 | } 86 | FixSample( samp ); 87 | return ERR_NONE; 88 | } 89 | 90 | int Load_MOD_Pattern( Pattern* patt, u8 nchannels, u8* inst_count ) 91 | { 92 | u8 data1; 93 | u8 data2; 94 | u8 data3; 95 | u8 data4; 96 | 97 | u16 period; 98 | u8 inst; 99 | u8 effect; 100 | u8 param; 101 | 102 | u32 row; 103 | u32 col; 104 | 105 | PatternEntry* p; 106 | 107 | memset( patt, 0, sizeof( Pattern ) ); 108 | patt->nrows = 64; // MODs have fixed 64 rows per pattern 109 | 110 | for( row = 0; row < 64*MAX_CHANNELS; row++ ) 111 | { 112 | patt->data[row].note = 250; 113 | } 114 | 115 | for( row = 0; row < 64; row++ ) 116 | { 117 | for( col = 0; col < nchannels; col++ ) 118 | { 119 | data1 = read8(); // +-------------------------------------+ 120 | data2 = read8(); // | Byte 0 Byte 1 Byte 2 Byte 3 | 121 | data3 = read8(); // |-------------------------------------| 122 | data4 = read8(); // |aaaaBBBB CCCCCCCCC DDDDeeee FFFFFFFFF| 123 | // +-------------------------------------+ 124 | 125 | period = (data1&0xf)*256 + (data2); // BBBBCCCCCCCC = sample period value 126 | inst = (data1&0xF0)+(data3>>4); // aaaaDDDD = sample number 127 | effect = data3&0xF; // eeee = effect number 128 | param = data4; // FFFFFFFF = effect parameters 129 | 130 | // fix parameter for certain MOD effects 131 | switch( effect ) 132 | { 133 | case 5: // 5xy glis+slide 134 | case 6: // 6xy vib+slide 135 | if( param & 0xF0 ) // clear Y if X 136 | param &= 0xF0; 137 | } 138 | 139 | p = &patt->data[row*MAX_CHANNELS+col]; // copy data to pattern entry 140 | p->inst = inst; // ... 141 | CONV_XM_EFFECT( &effect, ¶m ); // ... 142 | p->fx = effect; // ... 143 | p->param = param; // ... 144 | 145 | if( period != 0 ) // 0 = no note, otherwise calculate note value from the amiga period 146 | p->note = (int)round(12.0*log( (856.0)/(double)period )/log(2)) + 37 + 11; 147 | if( *inst_count < (inst + 1) ) 148 | { 149 | *inst_count = (inst + 1); 150 | if( *inst_count > 31 ) 151 | *inst_count = 31; 152 | } 153 | } 154 | } 155 | return ERR_NONE; 156 | } 157 | 158 | int Load_MOD_Sample( Sample* samp, bool verbose, int index ) 159 | { 160 | int finetune; 161 | int x; 162 | 163 | memset( samp, 0, sizeof( Sample ) ); 164 | samp->msl_index = 0xFFFF; 165 | for( x = 0; x < 22; x++ ) 166 | samp->name[x] = read8(); // read in 22 bytes, store as SAMPLE_NAME 167 | for( x = 0; x < 12; x++ ) // copy to filename 168 | samp->filename[x] = samp->name[x]; 169 | samp->sample_length = (read8()*256 + read8()) * 2; // read in 2 bytes (word), store as SAMPLE_LENGTH 170 | finetune = read8(); // read in 1 byte, store as FINE_TUNE 171 | if( finetune >= 8 ) finetune -= 16; 172 | 173 | samp->default_volume = read8(); // read in 1 byte, store as VOLUME 174 | samp->loop_start = (read8()*256 + read8()) * 2; // read in 2 bytes (word), store as LOOP_START 175 | samp->loop_end = samp->loop_start + (read8()*256+read8())*2; // read in 2 bytes (word), store as LOOP_LENGTH 176 | 177 | // IS THIS WRONG?? : 178 | samp->frequency = (int)(8363.0 * pow( 2.0, ((double)finetune) * (1.0/192.0) ) ); // calculate frequency... 179 | 180 | samp->global_volume=64; // max global volume 181 | if( (samp->loop_end - samp->loop_start) <= 2 ) // if loop length <= 2 then disabled loop 182 | { 183 | samp->loop_type = samp->loop_start = samp->loop_end = 0; 184 | } 185 | else 186 | { 187 | samp->loop_type = 1; // otherwise enable 188 | } 189 | if( verbose ) 190 | { 191 | if( samp->sample_length != 0 ) 192 | { 193 | //printf( "%i %s %i%% %ihz\n", samp->sample_length, samp->loop_type != 0 ? "Yes" : "No", (samp->default_volume*100)/64, samp->frequency ); 194 | printf( vstr_mod_samp, index, samp->sample_length, samp->loop_type != 0 ? "Yes" : "No", (samp->default_volume*100)/64, samp->frequency, samp->name ); 195 | /* 196 | printf( " Length......%i\n", samp->sample_length ); 197 | if( samp->loop_type != 0 ) 198 | { 199 | printf( " Loop........%i->%i\n", samp->loop_start, samp->loop_end ); 200 | } 201 | else 202 | { 203 | printf( " Loop........None\n" ); 204 | } 205 | printf( " Volume......%i\n", samp->default_volume ); 206 | printf( " Middle C....%ihz\n", samp->frequency );*/ 207 | } 208 | else 209 | { 210 | //printf( "---\n" ); 211 | } 212 | } 213 | return ERR_NONE; 214 | } 215 | 216 | int Load_MOD( MAS_Module* mod, bool verbose ) 217 | { 218 | u32 file_start; 219 | u32 mod_channels; 220 | int x; 221 | 222 | int npatterns; 223 | 224 | u32 sig; 225 | char sigs[5]; 226 | 227 | if( verbose ) 228 | printf( "Loading MOD, " ); 229 | 230 | memset( mod, 0, sizeof( MAS_Module ) ); 231 | file_start = file_tell_read(); 232 | file_seek_read( 0x438, SEEK_SET ); // Seek to offset 1080 (438h) in the file 233 | sig = read32(); // read in 4 bytes 234 | sigs[0]=sig&0xFF; 235 | sigs[1]=(sig>>8)&0xFF; 236 | sigs[2]=(sig>>16)&0xFF; 237 | sigs[3]=(sig>>24); 238 | sigs[4]=0; 239 | switch( sig ) 240 | { 241 | case 'NHC1': 242 | mod_channels=1; 243 | break; 244 | case 'NHC2': 245 | mod_channels=2; 246 | break; 247 | case 'NHC3': 248 | mod_channels=3; 249 | break; 250 | case '.K.M': // compare them to "M.K." - if true we have a 4 channel mod 251 | case 'NHC4': 252 | mod_channels=4; 253 | break; 254 | case 'NHC5': 255 | mod_channels=5; 256 | break; 257 | case 'NHC6': 258 | mod_channels=6; // compare them to "6CHN" - if true we have a 6 channel mod 259 | break; 260 | case 'NHC7': 261 | mod_channels=7; 262 | break; 263 | case 'NHC8': // compare them to "8CHN" - if true we have an 8 channel mod 264 | mod_channels=8; 265 | break; 266 | case 'NHC9': 267 | mod_channels=9; 268 | break; 269 | default: 270 | if( sig>>16 == 'HC' ) // There are also rare tunes that use **CH where ** = 10-32 channels 271 | { 272 | char chn_number[3]; 273 | chn_number[0] = (char)(sig&0xFF); 274 | chn_number[1] = (char)((sig>>8)&0xFF); 275 | chn_number[2] = 0; 276 | mod_channels = atoi( chn_number ); 277 | if( mod_channels > MAX_CHANNELS ) 278 | return ERR_MANYCHANNELS; 279 | } 280 | else 281 | { 282 | return ERR_INVALID_MODULE; // otherwise exit and display error message. 283 | } 284 | } 285 | 286 | file_seek_read( file_start, SEEK_SET ); // - Seek back to position 0, the start of the file 287 | for( x = 0; x < 20; x++ ) 288 | mod->title[x] = read8(); // - read in 20 bytes, store as MODULE_NAME. 289 | 290 | if( verbose ) 291 | { 292 | printf( "\"%s\"\n", mod->title ); 293 | printf( "%i channels (%s)\n", mod_channels, sigs ); 294 | } 295 | 296 | for( x = 0; x < MAX_CHANNELS; x++ ) 297 | { 298 | if( (x&3)!=1 && (x&3) != 2 ) 299 | mod->channel_panning[x] = clamp_u8( 128 - (PANNING_SEP/2) ); 300 | else 301 | mod->channel_panning[x] = clamp_u8( 128 + (PANNING_SEP/2) ); 302 | mod->channel_volume[x] = 64; 303 | } 304 | 305 | // set MOD settings 306 | mod->freq_mode = 0; 307 | mod->global_volume = 64; 308 | mod->initial_speed = 6; 309 | mod->initial_tempo = 125; 310 | mod->inst_count = 0; // filled in by Load_MOD_Pattern 311 | mod->inst_mode = false; 312 | mod->instruments = (Instrument*)malloc( 31 * sizeof( Instrument ) ); 313 | mod->link_gxx = false; 314 | mod->old_effects = true; 315 | mod->restart_pos = 0; 316 | mod->samp_count = 0; // filled in before Load_MOD_SampleData 317 | mod->samples = (Sample*)malloc( 31 * sizeof( Sample ) ); 318 | mod->stereo = true; 319 | mod->xm_mode = true; 320 | mod->old_mode=true; 321 | 322 | if( verbose ) 323 | { 324 | printf( vstr_mod_div ); 325 | printf( "Loading Samples...\n" ); 326 | printf( vstr_mod_samp_top ); 327 | printf( vstr_mod_samp_header ); 328 | #ifdef vstr_mod_samp_slice 329 | printf( vstr_mod_samp_slice ); 330 | #endif 331 | } 332 | // Load Sample Information 333 | for( x = 0; x < 31; x++ ) 334 | { 335 | // if( verbose ) 336 | //printf( "Loading Sample %i...\n", x+1 ); 337 | Create_MOD_Instrument( &mod->instruments[x], (u8)x ); 338 | Load_MOD_Sample( &mod->samples[x], verbose, x ); 339 | } 340 | 341 | // read sequence 342 | mod->order_count = read8(); // read a byte, store as SONG_LENGTH (this is the number of orders in a song) 343 | mod->restart_pos = read8(); // read a byte, discard it (this is the UNUSED byte - used to be used in PT as the restart position, but not now since jump to pattern was introduced) 344 | if( mod->restart_pos >= 127 ) 345 | mod->restart_pos=0; 346 | npatterns=0; // set NUMBER_OF_PATTERNS to equal 0......... or -1 :) 347 | for( x = 0; x < 128; x++ ) // from this point, loop 128 times 348 | { 349 | mod->orders[x] = read8(); // read 1 byte, store it as ORDER 350 | if( mod->orders[x] >= npatterns ) // if this value was bigger than NUMBER_OF_PATTERNS then set it to that value. 351 | npatterns=mod->orders[x]+1; 352 | } 353 | 354 | read32(); // read 4 bytes, discard them (we are at position 1080 again, this is M.K. etc!) 355 | mod->patt_count = npatterns; 356 | mod->patterns = (Pattern*)malloc( mod->patt_count * sizeof( Pattern ) ); // allocate patterns 357 | 358 | if( verbose ) 359 | { 360 | printf( vstr_mod_samp_bottom ); 361 | printf( "Sequence has %i entries.\n", mod->order_count ); 362 | printf( "Module has %i pattern%s.\n", mod->patt_count, mod->patt_count==1?"":"s" ); 363 | printf( vstr_mod_div ); 364 | printf( "Loading Patterns...\n" ); 365 | printf( vstr_mod_div ); 366 | } 367 | 368 | // Load Patterns 369 | for( x = 0; x < mod->patt_count; x++ ) 370 | { 371 | if( verbose ) 372 | { 373 | printf( vstr_mod_pattern, x+1, ((x+1)%15)?"":"\n" ); 374 | } 375 | Load_MOD_Pattern( &mod->patterns[x], (u8)mod_channels, &(mod->inst_count) ); 376 | } 377 | if( verbose ) 378 | { 379 | printf( "\n" ); 380 | printf( vstr_mod_div ); 381 | } 382 | // Load Sample Data 383 | if( verbose ) 384 | printf( "Loading Sample Data...\n" ); 385 | mod->samp_count = mod->inst_count; 386 | for( x = 0; x < 31; x++ ) 387 | { 388 | Load_MOD_SampleData( &mod->samples[x] ); 389 | } 390 | if( verbose ) 391 | printf( vstr_mod_div ); 392 | return ERR_NONE; 393 | } 394 | -------------------------------------------------------------------------------- /source/mod.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 26 | #include 27 | #include 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 | u8 target_sformat; 98 | 99 | u32 h_filesize; 100 | int samp_id; 101 | bool samp_match; 102 | 103 | int fsize=file_size( TMP_SAMP ); 104 | if( fsize == 0 ) 105 | { 106 | return MSL_AddSample( samp ); 107 | } 108 | F_SAMP = fopen( TMP_SAMP, "rb" ); 109 | fseek( F_SAMP, 0, SEEK_SET ); 110 | samp_id = 0; 111 | while( ftell( F_SAMP ) < fsize ) 112 | { 113 | h_filesize = read32f( F_SAMP ); 114 | read32f( F_SAMP ); 115 | samp_len = read32f( F_SAMP ); 116 | samp_llen = read32f( F_SAMP ); 117 | sformat = read8f( F_SAMP ); 118 | skip8f( 3, F_SAMP ); 119 | if( target_system == SYSTEM_NDS ) 120 | { 121 | target_sformat = sample_dsformat( samp ); 122 | skip8f(4,F_SAMP); 123 | } 124 | else 125 | { 126 | target_sformat = SAMP_FORMAT_U8; 127 | } 128 | 129 | samp_match=true; 130 | if( samp->sample_length == samp_len && ( samp->loop_type ? samp->loop_end-samp->loop_start : 0xFFFFFFFF ) == samp_llen && sformat == target_sformat ) 131 | { 132 | // verify sample data 133 | if( samp->format & SAMPF_16BIT ) 134 | { 135 | for( st=0; stdata)[st] ) 138 | { 139 | samp_match = false; 140 | break; 141 | } 142 | } 143 | } 144 | else 145 | { 146 | for( st=0; stdata)[st] ) 149 | { 150 | samp_match = false; 151 | break; 152 | } 153 | } 154 | } 155 | if( samp_match ) 156 | { 157 | fclose( F_SAMP ); 158 | return samp_id; 159 | } 160 | else 161 | { 162 | skip8f( (h_filesize-SAMPLE_HEADER_SIZE ) - (st+1) , F_SAMP ); // +4 to skip padding 163 | } 164 | } 165 | else 166 | { 167 | skip8f( h_filesize- SAMPLE_HEADER_SIZE , F_SAMP ); // +4 to skip padding 168 | } 169 | samp_id++; 170 | } 171 | fclose( F_SAMP ); 172 | return MSL_AddSample( samp ); 173 | } 174 | 175 | u16 MSL_AddModule( MAS_Module* mod ) 176 | { 177 | int x; 178 | int samp_id; 179 | // ADD SAMPLES 180 | for( x = 0; x < mod->samp_count; x++ ) 181 | { 182 | samp_id = MSL_AddSampleC( &mod->samples[x] ); 183 | if( mod->samples[x].filename[0] == '#' ) 184 | MSL_PrintDefinition( mod->samples[x].filename+1, (u16)samp_id, "SFX_" ); 185 | mod->samples[x].msl_index = samp_id; 186 | } 187 | 188 | file_open_write_end( TMP_SONG ); 189 | Write_MAS( mod, false, true ); 190 | file_close_write(); 191 | MSL_NSONGS++; 192 | return MSL_NSONGS-1; 193 | } 194 | 195 | void MSL_Export( char* filename ) 196 | { 197 | u32 x; 198 | u32 y; 199 | u32 file_size; 200 | 201 | u32* parap_samp; 202 | u32* parap_song; 203 | 204 | file_open_write( filename ); 205 | write16( MSL_NSAMPS ); 206 | write16( MSL_NSONGS ); 207 | write8( '*' ); 208 | write8( 'm' ); 209 | write8( 'a' ); 210 | write8( 'x' ); 211 | write8( 'm' ); 212 | write8( 'o' ); 213 | write8( 'd' ); 214 | write8( '*' ); 215 | 216 | parap_samp = (u32*)malloc( MSL_NSAMPS * sizeof( u32 ) ); 217 | parap_song = (u32*)malloc( MSL_NSONGS * sizeof( u32 ) ); 218 | 219 | // reserve space for parapointers 220 | for( x = 0; x < MSL_NSAMPS; x++ ) 221 | write32( 0xAAAAAAAA ); 222 | for( x = 0; x < MSL_NSONGS; x++ ) 223 | write32( 0xAAAAAAAA ); 224 | // copy samples 225 | file_open_read( TMP_SAMP ); 226 | for( x = 0; x < MSL_NSAMPS; x++ ) 227 | { 228 | align32(); 229 | parap_samp[x] = file_tell_write(); 230 | file_size = read32(); 231 | write32( file_size ); 232 | for( y = 0; y < file_size+4; y++ ) 233 | write8( read8() ); 234 | } 235 | file_close_read(); 236 | 237 | file_open_read( TMP_SONG ); 238 | for( x = 0; x < MSL_NSONGS; x++ ) 239 | { 240 | align32(); 241 | parap_song[x] = file_tell_write(); 242 | file_size = read32(); 243 | write32( file_size ); 244 | for( y = 0; y < file_size+4; y++ ) 245 | write8( read8() ); 246 | } 247 | file_close_read(); 248 | 249 | file_seek_write( 0x0C, SEEK_SET ); 250 | for( x = 0; x < MSL_NSAMPS; x++ ) 251 | write32( parap_samp[x] ); 252 | for( x= 0; x < MSL_NSONGS; x++ ) 253 | write32( parap_song[x] ); 254 | 255 | file_close_write(); 256 | 257 | if( parap_samp ) 258 | free( parap_samp ); 259 | if( parap_song ) 260 | free( parap_song ); 261 | } 262 | 263 | void MSL_PrintDefinition( char* filename, u16 id, char* prefix ) 264 | { 265 | char newtitle[64]; 266 | int x,s=0; 267 | if( filename[0] == 0 ) // empty string 268 | return; 269 | for( x = 0; x < (int)strlen( filename ); x++ ) 270 | { 271 | if( filename[x] == '\\' || filename[x] == '/' ) s = x+1; 272 | } 273 | for( x = s; x < (int)strlen( filename ); x++ ) 274 | { 275 | if( filename[x] != '.' ) 276 | { 277 | newtitle[x-s] = toupper(filename[x]); 278 | if( newtitle[x-s] >= ' ' && newtitle[x-s] <= '/' ) 279 | newtitle[x-s] = '_'; 280 | if( newtitle[x-s] >= ':' && newtitle[x-s] <= '@' ) 281 | newtitle[x-s] = '_'; 282 | if( newtitle[x-s] >= '[' && newtitle[x-s] <= '`' ) 283 | newtitle[x-s] = '_'; 284 | if( newtitle[x-s] >= '{' ) 285 | newtitle[x-s] = '_'; 286 | } 287 | else 288 | { 289 | break; 290 | } 291 | } 292 | newtitle[x-s] = 0; 293 | if( F_HEADER ) 294 | { 295 | fprintf( F_HEADER, "#define %s%s %i\r\n", prefix, newtitle, id ); 296 | } 297 | } 298 | 299 | void MSL_LoadFile( char* filename, bool verbose ) 300 | { 301 | Sample wav; 302 | MAS_Module mod; 303 | int f_ext; 304 | if( file_open_read( filename ) ) 305 | { 306 | printf( "Cannot open %s for reading! Skipping.\n", filename ); 307 | return; 308 | } 309 | f_ext = get_ext( filename ); 310 | switch( f_ext ) 311 | { 312 | case INPUT_TYPE_MOD: 313 | Load_MOD( &mod, verbose ); 314 | MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" ); 315 | Delete_Module( &mod ); 316 | break; 317 | case INPUT_TYPE_S3M: 318 | Load_S3M( &mod, verbose ); 319 | MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" ); 320 | Delete_Module( &mod ); 321 | break; 322 | case INPUT_TYPE_XM: 323 | Load_XM( &mod, verbose ); 324 | MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" ); 325 | Delete_Module( &mod ); 326 | break; 327 | case INPUT_TYPE_IT: 328 | Load_IT( &mod, verbose ); 329 | MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" ); 330 | Delete_Module( &mod ); 331 | break; 332 | case INPUT_TYPE_WAV: 333 | Load_WAV( &wav, verbose, true ); 334 | wav.filename[0] = '#'; // set SFX flag (for demo) 335 | MSL_PrintDefinition( filename, MSL_AddSample( &wav ), "SFX_" ); 336 | free( wav.data ); 337 | break; 338 | default: 339 | // print error/warning 340 | printf( "Unknown file %s...\n", filename ); 341 | } 342 | file_close_read(); 343 | 344 | } 345 | 346 | int MSL_Create( char* argv[], int argc, char* output, char* header, bool verbose ) 347 | { 348 | // int str_w=0; 349 | // u8 pmode=0; 350 | // bool comment=false; 351 | 352 | int x; 353 | 354 | MSL_Erase(); 355 | str_msl[0] = 0; 356 | F_HEADER=NULL; 357 | if( header ) 358 | { 359 | F_HEADER = fopen( header, "wb" ); 360 | } 361 | 362 | // if( !F_HEADER ) 363 | // return -1; // needs header file! 364 | 365 | file_open_write( TMP_SAMP ); 366 | file_close_write(); 367 | file_open_write( TMP_SONG ); 368 | file_close_write(); 369 | 370 | for( x = 1; x < argc; x++ ) 371 | { 372 | if( argv[x][0] == '-' ) 373 | { 374 | 375 | } 376 | else 377 | { 378 | MSL_LoadFile( argv[x], verbose ); 379 | } 380 | } 381 | 382 | MSL_Export( output ); 383 | 384 | if( F_HEADER ) 385 | { 386 | fprintf( F_HEADER, "#define MSL_NSONGS %i\r\n", MSL_NSONGS ); 387 | fprintf( F_HEADER, "#define MSL_NSAMPS %i\r\n", MSL_NSAMPS ); 388 | fprintf( F_HEADER, "#define MSL_BANKSIZE %i\r\n", (MSL_NSAMPS+MSL_NSONGS) ); 389 | fclose( F_HEADER ); 390 | F_HEADER=NULL; 391 | } 392 | 393 | file_delete( TMP_SAMP ); 394 | file_delete( TMP_SONG ); 395 | return ERR_NONE; 396 | } -------------------------------------------------------------------------------- /source/msl.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 28 | #include "defs.h" 29 | #include "files.h" 30 | #include "mas.h" 31 | 32 | #include "arm7_st.inc" 33 | #include "arm9_st.inc" 34 | 35 | const u8 nds_logo[]; 36 | 37 | #define ARM7_SIZE sizeof(arm7_bin) 38 | #define ARM9_SIZE sizeof(arm9_bin) 39 | 40 | const unsigned short crc16tab[] = 41 | { 42 | 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 43 | 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 44 | 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 45 | 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 46 | 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 47 | 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 48 | 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 49 | 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 50 | 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 51 | 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 52 | 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 53 | 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 54 | 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 55 | 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 56 | 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 57 | 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 58 | 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 59 | 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 60 | 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 61 | 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 62 | 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 63 | 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 64 | 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 65 | 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 66 | 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 67 | 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 68 | 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 69 | 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 70 | 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 71 | 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 72 | 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 73 | 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 74 | }; 75 | 76 | void Write_NDS( void ) 77 | { 78 | int x; 79 | const char game_title[] = "SOUND TEST "; 80 | 81 | for( x = 0; x < 12; x++ ) 82 | write8( game_title[x] ); 83 | 84 | write32( '####' ); // gamecode 85 | write16( 0 ); // makercode 86 | write8( 0 ); // unit code (Nintendo DS) 87 | write8( 0 ); // encryption seed 88 | write8( 0 ); // device capability 89 | for( x= 0; x < 9; x++ ) 90 | write8( 0 ); // reserved 91 | write8( 0 ); // rom version 92 | write8( 4 ); // autostart 93 | 94 | //----------------------------------------------------------- 95 | write32( 512+32768 ); // arm9 ROM offset 96 | write32( 0x2000000 ); // arm9 entry point 97 | write32( 0x2000000 ); // arm9 ram address 98 | write32( 65536 ); // arm9 binary size (modify later) 99 | //----------------------------------------------------------- 100 | write32( 512 ); // arm7 ROM offset 101 | write32( 0x37f8000 ); // arm7 entry point 102 | write32( 0x37f8000 ); // arm7 ram address 103 | write32( 32768 ); // arm7 binary size 104 | //----------------------------------------------------------- 105 | 106 | write32( 0 ); // fnt address 107 | write32( 0 ); // fnt size 108 | write32( 0 ); // fat address 109 | write32( 0 ); // fat size 110 | 111 | write32( 0 ); // file arm9 overlay address 112 | write32( 0 ); // file arm9 overlay size 113 | write32( 0 ); // file arm7 overlay address 114 | write32( 0 ); // file arm7 overlay size 115 | 116 | write32( 0x7f7fff ); // port 40001a4 setting for normal commands 117 | write32( 0x203f1fff ); // port 40001a4 setting for KEY1 commands 118 | 119 | write32( 0 ); // icon (no icon) 120 | 121 | write16( 0 ); // secure area checksum 122 | write16( 0x51e ); // secure area loading timeout 123 | write32( 0 ); // arm9 auto load list RAM address (?) 124 | write32( 0 ); // arm7 auto load list RAM address (?) 125 | write32( 0 ); // secure area disable 126 | write32( 0 ); // secure area disable 127 | 128 | write32( 0x14400 ); // total used ROM size 129 | write32( 0x200 ); // rom header size 130 | 131 | write32( 0 ); 132 | write32( 0 ); 133 | write32( 0 ); 134 | write32( 0 ); 135 | write32( 0 ); 136 | write32( 0 ); 137 | write32( 'MARS' ); 138 | write32( '11V_' ); 139 | write8( '0' ); 140 | write8( 0 );write8( 0 );write8( 0 ); 141 | write32( 'SSAP' ); 142 | write8( '0' );write8( '1' );write8( 0x96 );write8( 0 ); 143 | 144 | write32( 0 ); 145 | write32( 0 ); 146 | write32( 0 ); 147 | 148 | for( x = 0; x < 0x9c; x++ ) 149 | write8( nds_logo[x] ); // NINTENDO LOGO 150 | 151 | write16( 0x9e1a ); // nintendo logo checksum 152 | write16( 0 ); // header checksum (modify later) 153 | write32( 0 ); // debug rom offset 154 | write32( 0 ); // debug rom size 155 | write32( 0 ); // debug ram address 156 | 157 | write32( 0 ); // reserved 158 | 159 | for( x = 0; x < 0x90; x++ ) 160 | write8( 0 ); 161 | 162 | // write binaries 163 | for( x = 0; x < ARM7_SIZE; x++ ) 164 | write8( arm7_bin[x] ); 165 | for( x = 0; x < 32768-ARM7_SIZE; x++ ) // pad to 32k 166 | write8( (u8)x ); 167 | for( x = 0; x < ARM9_SIZE; x++ ) 168 | write8( arm9_bin[x] ); 169 | for( x = 0; x < 65536-ARM9_SIZE; x++ ) // pad to 64k 170 | write8( (u8)x ); 171 | } 172 | 173 | unsigned short calculate_crc( void ) 174 | { 175 | int i; 176 | unsigned short crc = 0xFFFF; 177 | for ( i=0; i<0x15E; i++) 178 | { 179 | unsigned char data = read8(); 180 | crc = (crc >> 8) ^ crc16tab[(crc ^ data) & 0xFF]; 181 | } 182 | return crc; 183 | } 184 | 185 | void Validate_NDS( char* filename, int output_size ) 186 | { 187 | int arm9_size; 188 | int header_crc; 189 | arm9_size = 65536 + output_size; 190 | file_open_write_end( filename ); 191 | file_seek_write( 0x2c, SEEK_SET ); 192 | write32( arm9_size ); 193 | file_seek_write( 0x80, SEEK_SET ); 194 | write32( arm9_size+32768 ); // total used rom size 195 | file_close_write(); 196 | 197 | file_open_read( filename ); 198 | header_crc=calculate_crc(); 199 | file_close_read(); 200 | header_crc &= 0xFFFF; 201 | 202 | file_open_write_end( filename ); 203 | file_seek_write( 0x15e, SEEK_SET ); 204 | write16( (u16)header_crc ); 205 | file_close_write(); 206 | /* 207 | // write arm7 rom_offset 208 | file_seek_write( 0x30, SEEK_SET ); 209 | write32( 512 ); 210 | 211 | // write arm9 rom_offset 212 | file_seek_write( 0x20, SEEK_SET ); 213 | write32( 512 + 0x4000 ); 214 | 215 | // write arm9 size 216 | file_seek_write( 0x2C, SEEK_SET ); 217 | write32( 0x10000 + output_size ); 218 | */ 219 | } 220 | 221 | const u8 nds_logo[] = { 222 | 0xC8, 0x60, 0x4F, 0xE2, 0x1, 0x70, 0x8F, 0xE2, 0x17, 0xFF, 0x2F, 0xE1, 0x12, 0x4F, 0x11, 0x48, 0x12, 0x4C, 0x20, 0x60, 0x64, 0x60, 0x7C, 0x62, 0x30, 0x1C, 0x39, 0x1C, 0x10, 0x4A, 0x0, 0xF0, 0x14, 0xF8, 223 | 0x30, 0x6A, 0x80, 0x19, 0xB1, 0x6A, 0xF2, 0x6A, 0x0, 0xF0, 0xB, 0xF8, 0x30, 0x6B, 0x80, 0x19, 0xB1, 0x6B, 0xF2, 0x6B, 0x0, 0xF0, 0x8, 0xF8, 0x70, 0x6A, 0x77, 0x6B, 0x7, 0x4C, 0x60, 0x60, 0x38, 0x47, 0x7, 224 | 0x4B, 0xD2, 0x18, 0x9A, 0x43, 0x7, 0x4B, 0x92, 0x8, 0xD2, 0x18, 0xC, 0xDF, 0xF7, 0x46, 0x4, 0xF0, 0x1F, 0xE5, 0x0, 0xFE, 0x7F, 0x2, 0xF0, 0xFF, 0x7F, 0x2, 0xF0, 0x1, 0x0, 0x0, 0xFF, 0x1, 0x0, 0x0, 0x0, 225 | 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 226 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; 227 | -------------------------------------------------------------------------------- /source/nds.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 26 | #include 27 | #include "defs.h" 28 | #include "mas.h" 29 | #include "s3m.h" 30 | #include "files.h" 31 | #include "simple.h" 32 | #include "errors.h" 33 | #include "samplefix.h" 34 | 35 | #define S3M_NOTE(a) (((a&15)+(a>>4)*12)+12) 36 | 37 | #ifdef SUPER_ASCII 38 | #define vstr_s3m_samp " %5i │ %-4s│ %3i%% │%5ihz│ %-28s│\n" 39 | #define vstr_s3m_sampe " ----- │ --- │ ---- │ ----- │ %-28s│\n" 40 | #define vstr_s3m_div "────────────────────────────────────────────\n" 41 | #define vstr_s3m_sampt_top "┌─────┬───────┬─────┬──────┬───────┬─────────────────────────────┐\n" 42 | #define vstr_s3m_sampt_mid "│INDEX│LENGTH │LOOP │VOLUME│ MID-C │ NAME │\n" 43 | #define vstr_s3m_sampt_slice "├─────┼───────┼─────┼──────┼───────┼─────────────────────────────┤\n" 44 | #define vstr_s3m_sampt_index "│ %2i │" 45 | #define vstr_s3m_sampt_bottom "└─────┴───────┴─────┴──────┴───────┴─────────────────────────────┘\n" 46 | #define vstr_s3m_pattern " \x0e %2i%s" 47 | #else 48 | #define vstr_s3m_samp "%-5i %-3s %3i%% %5ihz %-28s \n" 49 | #define vstr_s3m_sampe "----- --- ---- ------- %-28s\n" 50 | #define vstr_s3m_div "--------------------------------------------\n" 51 | #define vstr_s3m_sampt_top vstr_s3m_div 52 | #define vstr_s3m_sampt_mid " INDEX LENGTH LOOP VOLUME MID-C NAME\n" 53 | //#define vstr_s3m_sampt_slice "" 54 | #define vstr_s3m_sampt_index " %-2i " 55 | #define vstr_s3m_sampt_bottom vstr_s3m_div 56 | #define vstr_s3m_pattern " * %2i%s" 57 | #endif 58 | 59 | int Load_S3M_SampleData( Sample* samp, u8 ffi ) 60 | { 61 | u32 x; 62 | int a; 63 | if( samp->sample_length == 0 ) 64 | return ERR_NONE; 65 | if( samp->format & SAMPF_16BIT ) 66 | samp->data = (u16*)malloc( samp->sample_length*2 ); 67 | else 68 | samp->data = (u8*)malloc( samp->sample_length ); 69 | if( ffi == 1 ) 70 | { 71 | // signed samples [VERY OLD] 72 | for( x = 0; x < samp->sample_length; x++ ) 73 | { 74 | if( samp->format & SAMPF_16BIT ) 75 | { 76 | a = read16(); 77 | a += 32768; 78 | ((u16*)samp->data)[x] = (u16)a; 79 | } 80 | else 81 | { 82 | a = read8(); 83 | a += 128; 84 | ((u8*)samp->data)[x] = (u8)a; 85 | } 86 | } 87 | } 88 | else if( ffi == 2 ) 89 | { 90 | // unsigned samples 91 | for( x = 0; x < samp->sample_length; x++ ) 92 | { 93 | if( samp->format & SAMPF_16BIT ) 94 | { 95 | a = read16(); 96 | ((u16*)samp->data)[x] = (u16)a; 97 | } 98 | else 99 | { 100 | a = read8(); 101 | ((u8*)samp->data)[x] = (u8)a; 102 | } 103 | } 104 | } 105 | else 106 | { 107 | return ERR_UNKNOWNSAMPLE; 108 | } 109 | FixSample( samp ); 110 | return ERR_NONE; 111 | } 112 | 113 | int Load_S3M_Sample( Sample* samp, bool verbose ) 114 | { 115 | u8 flags; 116 | u32 x; 117 | memset( samp, 0, sizeof( Sample ) ); 118 | samp->msl_index = 0xFFFF; 119 | if( read8() == 1 ) // type, 1 = sample 120 | { 121 | for( x = 0; x < 12; x++ ) 122 | samp->filename[x] = read8(); 123 | samp->datapointer = (read8()*65536+read16())*16;//read24(); 124 | samp->sample_length = read32(); 125 | samp->loop_start = read32(); 126 | samp->loop_end = read32(); 127 | samp->default_volume = read8(); 128 | samp->global_volume = 64; 129 | read8(); // reserved 130 | if( read8() != 0 ) // packing, 0 = unpacked 131 | return ERR_UNKNOWNSAMPLE; 132 | flags = read8(); 133 | samp->loop_type = flags&1 ? 1 : 0; 134 | if( flags & 2 ) 135 | return ERR_UNKNOWNSAMPLE; 136 | //samp->bit16 = flags&4 ? true : false; 137 | samp->format = flags&4 ? SAMP_FORMAT_U16 : SAMP_FORMAT_U8; 138 | samp->frequency = read32(); 139 | read32(); // reserved 140 | skip8( 8 ); // internal variables 141 | for( x =0 ; x < 28; x++ ) 142 | samp->name[x] = read8(); 143 | if( read32() != 'SRCS' ) 144 | return ERR_UNKNOWNSAMPLE; 145 | 146 | if( verbose ) 147 | { 148 | // printf( "────────────────────────────────────────────\n" ); 149 | // printf( "Loading Samples...\n" ); 150 | // printf( "┌─────┬──────┬────┬──────┬─────┬─────────────────────────────┐\n" ); 151 | // printf( "│LENGTH│LOOP│VOLUME│ MID-C │ NAME │\n"); 152 | // printf( "┼──────┼────┼──────┼─────┼─────────────────────────────┤\n" ); 153 | printf( vstr_s3m_samp, samp->sample_length, samp->loop_type ? "Yes" : "No", (samp->default_volume*100) / 64, samp->frequency, samp->name ); 154 | /*printf( " Name......%s\n", samp->name ); 155 | printf( " Length....%i\n", samp->sample_length ); 156 | if( samp->loop_type ) 157 | printf( " Loop......%i->%i\n", samp->loop_start, samp->loop_end ); 158 | else 159 | printf( " Loop......Disabled\n" ); 160 | printf( " Volume....%i\n", samp->default_volume ); 161 | printf( " Middle C..%ihz\n", samp->frequency ); 162 | if( samp->bit16 ) 163 | printf( " 16 bit....yes\n" );*/ 164 | } 165 | } 166 | else 167 | { 168 | if( verbose ) 169 | { 170 | printf( vstr_s3m_sampe, samp->name ); 171 | } 172 | } 173 | return ERR_NONE; 174 | } 175 | 176 | int Load_S3M_Pattern( Pattern* patt ) 177 | { 178 | int clength; 179 | int row, col; 180 | u8 what; 181 | int z; 182 | 183 | clength = read16(); 184 | // unpack s3m data 185 | 186 | memset( patt, 0, sizeof( Pattern ) ); 187 | 188 | patt->clength = clength; 189 | patt->nrows = 64; 190 | 191 | for( row = 0; row < 64*MAX_CHANNELS; row++ ) 192 | { 193 | patt->data[row].note = 250; 194 | patt->data[row].vol = 255; 195 | } 196 | 197 | for( row = 0; row < 64; row++ ) 198 | { 199 | while( (what = read8()) != 0 ) // BYTE:what / 0=end of row 200 | { 201 | col = what & 31; // &31=channel 202 | 203 | z = row*MAX_CHANNELS+col; 204 | 205 | if( what & 32 ) // &32=follows; BYTE:note, BYTE:instrument 206 | { 207 | patt->data[z].note = read8(); 208 | if( patt->data[z].note == 255 ) 209 | patt->data[z].note = 250; 210 | else if( patt->data[z].note == 254 ) 211 | patt->data[z].note = 254; 212 | else 213 | patt->data[z].note = S3M_NOTE( patt->data[z].note ); 214 | patt->data[z].inst = read8(); 215 | } 216 | 217 | if( what & 64 ) // &64=follows; BYTE:volume 218 | { 219 | patt->data[z].vol = read8(); 220 | } 221 | 222 | if( what & 128 ) // &128=follows; BYTE:command, BYTE:info 223 | { 224 | patt->data[z].fx = read8(); 225 | patt->data[z].param = read8(); 226 | if( patt->data[z].fx == 3 ) // convert pattern break to hexadecimal 227 | { 228 | patt->data[z].param = (patt->data[z].param&0xF) + (patt->data[z].param/16)*10; 229 | } 230 | if( patt->data[z].fx == 'X'-64 ) 231 | { 232 | patt->data[z].param *= 2; // multiply volume scale by 2 233 | } 234 | if( patt->data[z].fx == 'V'-64 ) 235 | { 236 | patt->data[z].param *= 2; // multiply volume scale by 2 237 | } 238 | } 239 | if( patt->data[z].fx == 255 ) 240 | { 241 | patt->data[z].fx = 0; 242 | patt->data[z].param = 0; 243 | } 244 | } 245 | } 246 | return ERR_NONE; 247 | } 248 | 249 | int Load_S3M( MAS_Module* mod, bool verbose ) 250 | { 251 | u16 s3m_flags; 252 | u16 cwt; 253 | u16 ffi; 254 | u8 dp; 255 | 256 | bool stereo; 257 | 258 | u8 a; 259 | bool chan_enabled[32]; 260 | 261 | int x,y; 262 | 263 | u16* parap_inst; 264 | u16* parap_patt; 265 | 266 | 267 | 268 | memset( mod, 0, sizeof( MAS_Module ) ); 269 | for( x = 0; x < 28; x++ ) 270 | mod->title[x] = read8(); // read song name 271 | 272 | if( read8() != 0x1A ); 273 | // return ERR_INVALID_MODULE; 274 | if( read8() != 16 ) 275 | return ERR_INVALID_MODULE; 276 | if( verbose ) 277 | { 278 | printf( vstr_s3m_div ); 279 | } 280 | if( verbose ) 281 | printf( "Loading S3M, \"%s\"\n", mod->title ); 282 | 283 | skip8( 2 ); // reserved space 284 | mod->order_count = (u8)read16(); 285 | mod->inst_count = (u8)read16(); 286 | mod->samp_count = mod->inst_count; 287 | mod->patt_count = (u8)read16(); 288 | 289 | for( x = 0; x < 32; x++ ) 290 | mod->channel_volume[x] = 64; 291 | 292 | mod->freq_mode = 0; // amiga frequencies 293 | mod->old_effects=true; // old effects (maybe not?) 294 | mod->link_gxx=false; // dont link gxx memory 295 | mod->restart_pos = 0; // restart from beginning 296 | mod->old_mode=true; 297 | 298 | s3m_flags = read16(); 299 | cwt = read16(); 300 | ffi = read16(); 301 | if( read32() != 'MRCS' ) // "SCRM" mark 302 | return ERR_INVALID_MODULE; 303 | mod->global_volume = read8()*2; 304 | mod->initial_speed = read8(); 305 | mod->initial_tempo = read8(); 306 | stereo = read8() >> 7; // master volume 307 | read8(); // ultra click removal 308 | dp = read8(); // default pan positions (when 252) 309 | skip8( 8+2 ); // reserved space + special pointer 310 | for( x = 0; x < 32; x++ ) 311 | { 312 | u8 chn = read8(); 313 | chan_enabled[x] = chn >> 7; 314 | if( stereo ) 315 | { 316 | if( (chn&127) < 8 ) // left channel 317 | mod->channel_panning[x] = clamp_u8( 128 - (PANNING_SEP/2) ); 318 | else // right channel 319 | mod->channel_panning[x] = clamp_u8( 128 + (PANNING_SEP/2) ); 320 | } 321 | else 322 | { 323 | mod->channel_panning[x] = 128; 324 | } 325 | } 326 | for( x = 0; x < mod->order_count; x++ ) 327 | { 328 | mod->orders[x] = read8(); 329 | } 330 | parap_inst = (u16*)malloc( mod->inst_count * sizeof( u16 ) ); 331 | parap_patt = (u16*)malloc( mod->patt_count * sizeof( u16 ) ); 332 | 333 | for( x = 0; x < mod->inst_count; x++ ) 334 | parap_inst[x] = read16(); 335 | for( x = 0; x < mod->patt_count; x++ ) 336 | parap_patt[x] = read16(); 337 | 338 | if( dp == 252 ) 339 | { 340 | for( x = 0; x < 32; x++ ) 341 | { 342 | a = read8(); 343 | if( a & 32 ) 344 | { 345 | mod->channel_panning[x] = (a&15)*16 > 255 ? 255 : (a&15)*16; 346 | } 347 | else 348 | {/* 349 | if( stereo ) 350 | { 351 | switch( x & 3 ) { 352 | case 0: 353 | case 3: 354 | mod->channel_panning[x] = clamp_u8( 128 - (PANNING_SEP/2) ); 355 | break; 356 | case 1: 357 | case 2: 358 | mod->channel_panning[x] = clamp_u8( 128 + (PANNING_SEP/2) ); 359 | } 360 | } 361 | else 362 | { 363 | mod->channel_panning[x] = 128; 364 | }*/ 365 | } 366 | } 367 | } 368 | else 369 | { 370 | for( x = 0; x < 32; x++ ) 371 | { 372 | if( stereo ) 373 | mod->channel_panning[x] = x & 1 ? clamp_u8( 128 - (PANNING_SEP/2) ) : clamp_u8( 128 + (PANNING_SEP/2) ); 374 | else 375 | mod->channel_panning[x] = 128; 376 | } 377 | } 378 | 379 | mod->instruments = (Instrument*)malloc( mod->inst_count * sizeof( Instrument ) ); 380 | mod->samples = (Sample*)malloc( mod->samp_count * sizeof( Sample ) ); 381 | mod->patterns = (Pattern*)malloc( mod->patt_count * sizeof( Pattern ) ); 382 | 383 | if( verbose ) 384 | { 385 | printf( vstr_s3m_div ); 386 | printf( "Loading Samples...\n" ); 387 | printf( vstr_s3m_sampt_top ); 388 | printf( vstr_s3m_sampt_mid ); 389 | #ifdef vstr_s3m_sampt_slice 390 | printf( vstr_s3m_sampt_slice ); 391 | #endif 392 | } 393 | // load instruments 394 | for( x = 0; x < mod->inst_count; x++ ) 395 | { 396 | if( verbose ) 397 | { 398 | printf( vstr_s3m_sampt_index, x+1 ); 399 | //printf( "Sample %i\n", x+1 ); 400 | } 401 | // create instrument for sample 402 | memset( &mod->instruments[x], 0, sizeof( Instrument ) ); 403 | mod->instruments[x].global_volume = 128; 404 | // make notemap 405 | for( y = 0; y < 120; y++ ) 406 | mod->instruments[x].notemap[y] = y | ((x+1) << 8); 407 | 408 | // load sample 409 | file_seek_read( parap_inst[x]*16, SEEK_SET ); 410 | if( Load_S3M_Sample( &mod->samples[x], verbose ) ) 411 | { 412 | printf( "Error loading sample!\n" ); 413 | return ERR_UNKNOWNSAMPLE; 414 | } 415 | } 416 | 417 | // load patterns 418 | if( verbose ) 419 | { 420 | printf( vstr_s3m_sampt_bottom ); 421 | printf( "Loading Patterns...\n" ); 422 | printf( vstr_s3m_div ); 423 | } 424 | for( x = 0; x < mod->patt_count; x++ ) 425 | { 426 | if( verbose ) 427 | { 428 | printf( vstr_s3m_pattern, x+1, ((x+1)%15)?"":"\n" ); 429 | } 430 | //printf( "%i...", x+1 ); 431 | file_seek_read( parap_patt[x]*16, SEEK_SET ); 432 | Load_S3M_Pattern( &mod->patterns[x] ); 433 | } 434 | 435 | if( verbose ) 436 | { 437 | printf( "\n" ); 438 | printf( vstr_s3m_div ); 439 | printf( "Loading Sample Data...\n" ); 440 | } 441 | for( x = 0; x < mod->samp_count; x++ ) 442 | { 443 | file_seek_read( mod->samples[x].datapointer, SEEK_SET ); 444 | Load_S3M_SampleData( &mod->samples[x], (u8)ffi ); 445 | } 446 | if( verbose ) 447 | { 448 | printf( vstr_s3m_div ); 449 | } 450 | return ERR_NONE; 451 | } 452 | -------------------------------------------------------------------------------- /source/s3m.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 27 | #include 28 | #include 29 | #include "defs.h" 30 | #include "mas.h" 31 | #include "errors.h" 32 | #include "systems.h" 33 | #include "adpcm.h" 34 | 35 | extern int ignore_sflags; 36 | 37 | void Sample_PadStart( Sample* samp, u32 count ) 38 | { 39 | // Pad beginning of sample with zero 40 | u8* newdata8; 41 | u16* newdata16; 42 | u32 x; 43 | if( count == 0 ) 44 | return; // nothing to do 45 | if( samp->format & SAMPF_16BIT ) 46 | { 47 | newdata16 = (u16*)malloc( (samp->sample_length+count)*2 ); 48 | for( x = 0; x < count; x++ ) 49 | newdata16[x]=32768; 50 | for( x = 0; x < samp->sample_length; x++ ) 51 | newdata16[count+x]=((u16*)samp->data)[x]; 52 | free( samp->data ); 53 | samp->data = (void*)newdata16; 54 | } 55 | else 56 | { 57 | newdata8 = (u8*)malloc( (samp->sample_length+count) ); 58 | for( x = 0; x < count; x++ ) 59 | newdata8[x]=128; 60 | for( x = 0; x < samp->sample_length; x++ ) 61 | newdata8[count+x] = ((u8*)samp->data)[x]; 62 | free( samp->data ); 63 | samp->data = (void*)newdata8; 64 | } 65 | samp->loop_start += count; 66 | samp->loop_end += count; 67 | samp->sample_length += count; 68 | } 69 | 70 | void Sample_PadEnd( Sample* samp, u32 count ) 71 | { 72 | // Pad end of sample with zero 73 | u8* newdata8; 74 | u16* newdata16; 75 | u32 x; 76 | if( count == 0 ) 77 | return; // nothing to do 78 | if( samp->format & SAMPF_16BIT ) 79 | { 80 | newdata16 = malloc( (samp->sample_length+count)*2 ); 81 | for( x = 0; x < samp->sample_length; x++ ) 82 | newdata16[x]= ((u16*)samp->data)[x]; 83 | for( x = 0; x < count; x++ ) 84 | newdata16[samp->sample_length+x]=32768; 85 | free( samp->data ); 86 | samp->data = (void*)newdata16; 87 | } 88 | else 89 | { 90 | newdata8 = malloc( (samp->sample_length+count) ); 91 | for( x = 0; x < samp->sample_length; x++ ) 92 | newdata8[x]= ((u8*)samp->data)[x]; 93 | for( x = 0; x < count; x++ ) 94 | newdata8[samp->sample_length+x]=128; 95 | free( samp->data ); 96 | samp->data = (void*)newdata8; 97 | } 98 | samp->loop_end += count; 99 | samp->sample_length += count; 100 | } 101 | 102 | void Unroll_Sample_Loop( Sample* samp, u32 count ) 103 | { 104 | // unrolls sample loop (count) times 105 | // loop end MUST equal sample length 106 | u8* newdata8; 107 | u16* newdata16; 108 | u32 newlen; 109 | u32 looplen; 110 | u32 x; 111 | looplen = samp->loop_end-samp->loop_start; 112 | newlen = samp->sample_length + looplen*count; 113 | if( samp->format & SAMPF_16BIT ) 114 | { 115 | newdata16 = (u16*)malloc( newlen *2 ); 116 | for( x = 0; x < samp->sample_length; x++ ) 117 | newdata16[x] = ((u16*)samp->data)[x]; 118 | for( x = 0; x < looplen*count; x++ ) 119 | newdata16[samp->sample_length+x] = ((u16*)samp->data)[samp->loop_start+ (x%looplen)]; 120 | free( samp->data ); 121 | samp->data = (void*)newdata16; 122 | } 123 | else 124 | { 125 | newdata8 = (u8*)malloc( newlen ); 126 | for( x = 0; x < samp->sample_length; x++ ) 127 | newdata8[x] = ((u8*)samp->data)[x]; 128 | for( x = 0; x < looplen*count; x++ ) 129 | newdata8[samp->sample_length+x] = ((u8*)samp->data)[samp->loop_start+ (x%looplen)]; 130 | free( samp->data ); 131 | samp->data = (void*)newdata8; 132 | } 133 | samp->loop_end += looplen*count; 134 | samp->sample_length += looplen*count; 135 | } 136 | 137 | void Unroll_BIDI_Sample( Sample* samp ) 138 | { 139 | // sample length MUST equal sample loop end 140 | // sample MUST have loop type 2 (BIDI) 141 | u8* newdata8; 142 | u16* newdata16; 143 | u32 newlen; 144 | u32 looplen; 145 | u32 x; 146 | 147 | looplen = samp->loop_end-samp->loop_start; 148 | newlen = (samp->sample_length + looplen); 149 | 150 | if( samp->format & SAMPF_16BIT ) 151 | { 152 | newdata16 = malloc( newlen *2 ); 153 | for( x = 0; x < samp->sample_length; x++ ) 154 | newdata16[x] = ((u16*)samp->data)[x]; 155 | for( x = 0; x < looplen; x++ ) 156 | newdata16[x+samp->sample_length] = ((u16*)samp->data)[samp->loop_end-1-x]; 157 | free( samp->data ); 158 | samp->data = (void*)newdata16; 159 | } 160 | else 161 | { 162 | newdata8 = malloc( newlen ); 163 | for( x = 0; x < samp->sample_length; x++ ) 164 | newdata8[x] = ((u8*)samp->data)[x]; 165 | for( x = 0; x < looplen; x++ ) 166 | newdata8[x+samp->sample_length] = ((u8*)samp->data)[samp->loop_end-1-x]; 167 | free( samp->data ); 168 | samp->data = (void*)newdata8; 169 | } 170 | samp->loop_type = 1; 171 | samp->sample_length += looplen; 172 | samp->loop_end += looplen; 173 | } 174 | 175 | /* NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE 176 | The following resample routine was stolen from CHIBITRACKER (http://chibitracker.berlios.de), thanks reduz! 177 | NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE */ 178 | 179 | void Resample( Sample* samp, u32 newsize ) 180 | { 181 | // output pointers 182 | u8 *dst8 =0; 183 | u16 *dst16=0; 184 | u8 *src8 = (u8*)samp->data; 185 | u16 *src16 = (u16*)samp->data; 186 | 187 | int oldlength = samp->sample_length; 188 | int lpoint = samp->loop_start; 189 | int i; 190 | 191 | bool bit16 = samp->format & SAMPF_16BIT; 192 | double sign_diff; 193 | 194 | // allocate memory 195 | if( bit16 ) 196 | { 197 | dst16 = (u16*)malloc(newsize*2); 198 | sign_diff = 32768.0; 199 | } 200 | else 201 | { 202 | dst8 = (u8*)malloc(newsize); 203 | sign_diff = 128.0; 204 | } 205 | 206 | double tscale = (double)oldlength / (double)newsize; 207 | double posf; 208 | 209 | for( i = 0; i < newsize; i++ ) 210 | { 211 | posf = (double)i * tscale; 212 | int posi = (int)floor(posf); 213 | 214 | double mu = posf - (double)posi; 215 | double s0, s1, s2, s3; 216 | double mu2, a0, a1, a2, a3, res; 217 | 218 | // get previous, current, next, and after next samples 219 | if( bit16 ) 220 | { 221 | s0 = (posi-1) < 0 ? 0 : ((double)(src16[posi-1])); 222 | s1 = ((double)(src16[posi ])); 223 | s2 = (posi+1) >= oldlength ? 224 | (samp->loop_type ? 225 | ((double)(src16[lpoint + (posi + 1 - oldlength)])) : 0) : 226 | ((double)(src16[posi+1])); 227 | s3 = (posi+1) >= oldlength ? 228 | (samp->loop_type ? 229 | ((double)(src16[lpoint + (posi + 2 - oldlength)])) : 0) : 230 | ((double)(src16[posi+2])); 231 | } 232 | else 233 | { 234 | s0 = (posi-1) < 0 ? 0 : ((double)(src8[posi-1])); 235 | s1 = ((double)(src8[posi ])); 236 | s2 = (posi+1) >= oldlength ? 237 | (samp->loop_type ? 238 | ((double)(src8[lpoint + (posi + 1 - oldlength)])) : 0) : 239 | ((double)(src8[posi+1])); 240 | s3 = (posi+1) >= oldlength ? 241 | (samp->loop_type ? 242 | ((double)(src8[lpoint + (posi + 2 - oldlength)])) : 0) : 243 | ((double)(src8[posi+2])); 244 | } 245 | 246 | // sign data 247 | s0 -= sign_diff; 248 | s1 -= sign_diff; 249 | s2 -= sign_diff; 250 | s3 -= sign_diff; 251 | 252 | mu2 = mu * mu; 253 | a0 = s3 - s2 - s0 + s1; 254 | a1 = s0 - s1 - a0; 255 | a2 = s2 - s0; 256 | a3 = s1; 257 | 258 | res = a0*mu*mu2 + a1*mu2 + a2*mu + a3; 259 | int resi = ((int)floor(res+0.5)); 260 | 261 | if( bit16 ) 262 | { 263 | if( resi < -32768 ) resi = -32768; 264 | if( resi > 32767 ) resi = 32767; 265 | dst16[i] = resi + 32768; 266 | } 267 | else 268 | { 269 | if( resi < -128 ) resi = -128; 270 | if( resi > 127 ) resi = 127; 271 | dst8[i] = resi + 128; 272 | } 273 | 274 | } 275 | 276 | free( samp->data ); 277 | if( bit16 ) 278 | samp->data = (void*)dst16; 279 | else 280 | samp->data = (void*)dst8; 281 | 282 | samp->sample_length = newsize; 283 | samp->loop_end = newsize; 284 | samp->loop_start = (int)(((double)samp->loop_start * (double)newsize+((double)oldlength/2))/(double)oldlength); 285 | samp->frequency = (int)(((double)samp->frequency * (double)newsize+((double)oldlength/2))/(double)oldlength); 286 | } 287 | 288 | void Sample_8bit( Sample* samp ) 289 | { 290 | if( samp->format & SAMPF_16BIT ) 291 | { 292 | u8* newdata; 293 | u32 t; 294 | newdata = (u8*)malloc( samp->sample_length ); 295 | for( t = 0; t < samp->sample_length; t++ ) 296 | newdata[t] = ((u16*)samp->data)[t] / 256; 297 | free( samp->data ); 298 | samp->data = newdata; 299 | // samp->bit16=false; 300 | samp->format &= ~SAMPF_16BIT; 301 | } 302 | } 303 | 304 | void Sample_Sign( Sample* samp ) 305 | { 306 | // sample must be unsigned 307 | u32 x; 308 | if( samp->format & SAMPF_16BIT ) 309 | { 310 | for( x =0 ; x < samp->sample_length; x++ ) 311 | { 312 | int a = (( (int) ((u16*)samp->data)[x] ) - 32768); 313 | if(a < -32767) a = -32767; // clamp LOW to -32767 (leave space for interpolation error) 314 | // if(a > 32765) a = 32765; // clamp HIGH to 32766 315 | ((u16*)samp->data)[x] = (u16)a ; 316 | } 317 | } 318 | else 319 | { 320 | for( x =0 ; x < samp->sample_length; x++ ) 321 | { 322 | int a = (( (int) ((u8*)samp->data)[x] ) - 128); 323 | if( a == -128 ) a = -127; 324 | ((u8*)samp->data)[x] = (u8) a; 325 | } 326 | 327 | } 328 | samp->format |= SAMPF_SIGNED; 329 | } 330 | 331 | void FixSample_GBA( Sample* samp ) 332 | { 333 | // convert to 8-bit if neccesary 334 | Sample_8bit( samp ); 335 | 336 | // delete data after loop_end if loop exists 337 | if( samp->loop_type != 0 ) 338 | samp->sample_length = samp->loop_end; 339 | 340 | // unroll BIDI loop 341 | if( samp->loop_type == 2 ) 342 | Unroll_BIDI_Sample( samp ); 343 | 344 | if( samp->loop_type ) 345 | { 346 | if( samp->loop_end-samp->loop_start < GBA_MIN_LOOP_SIZE ) 347 | { 348 | Unroll_Sample_Loop( samp, (GBA_MIN_LOOP_SIZE / (samp->loop_end-samp->loop_start))+1 ); 349 | } 350 | } 351 | } 352 | 353 | int strcmpshit( char* str1, char* str2 ) 354 | { 355 | int x=0; 356 | int f=0; 357 | while( str1[x] != 0 ) 358 | { 359 | if( str1[x] == str2[f] )f++; 360 | else f=0; 361 | if( str2[f] == 0 ) return 1; 362 | x++; 363 | } 364 | return 0; 365 | } 366 | 367 | void FixSample_NDS( Sample* samp ) 368 | { 369 | if( samp->sample_length == 0 ) 370 | { 371 | // sample has no data 372 | samp->loop_end=samp->loop_start=0; 373 | return; 374 | } 375 | // delete data after loop_end if loop exists 376 | if( samp->loop_type != 0 ) 377 | samp->sample_length = samp->loop_end; 378 | 379 | // unroll BIDI loop 380 | if( samp->loop_type == 2 ) 381 | Unroll_BIDI_Sample( samp ); 382 | 383 | // %o option 384 | if( samp->loop_type ) 385 | { 386 | if( !ignore_sflags ) 387 | { 388 | if( ((strcmpshit( samp->name, "%o" )) > 0) ) 389 | { 390 | Unroll_Sample_Loop( samp, 1 ); 391 | samp->loop_start += (samp->loop_end-samp->loop_start) / 2; 392 | } 393 | } 394 | } 395 | 396 | if( !ignore_sflags ) 397 | { 398 | if( ((strcmpshit( samp->name, "%c" )) > 0) ) 399 | { 400 | samp->format |= SAMPF_COMP; 401 | } 402 | } 403 | 404 | // Resize loop 405 | if( samp->loop_type ) 406 | { 407 | int looplen = samp->loop_end-samp->loop_start; 408 | if( !(samp->format & SAMPF_COMP) ) 409 | { 410 | if( samp->format & SAMPF_16BIT ) 411 | { 412 | if( looplen & 1 ) 413 | { 414 | int addition = (samp->loop_end - samp->loop_start); 415 | if( addition > MAX_UNROLL_THRESHOLD ) 416 | Resample( samp, samp->sample_length +1 ); 417 | else 418 | Unroll_Sample_Loop( samp, 1 ); 419 | } 420 | } 421 | else 422 | { 423 | if( looplen & 3 ) 424 | { 425 | int count; 426 | int addition; 427 | count = looplen & 3; 428 | switch( count ) { 429 | case 0: 430 | count=0; break; 431 | case 1: 432 | count=3; break; 433 | case 2: 434 | count=1; break; 435 | case 3: 436 | count=3; break; 437 | } 438 | addition = looplen*count; 439 | if( addition > MAX_UNROLL_THRESHOLD ) 440 | Resample( samp, samp->sample_length + (4-(looplen & 3)) ); 441 | else 442 | Unroll_Sample_Loop( samp, count ); 443 | } 444 | } 445 | } 446 | else 447 | { 448 | int a = looplen; 449 | int count=0, addition; 450 | while( looplen & 7 ) 451 | { 452 | count++; 453 | looplen += a; 454 | } 455 | addition = looplen*count; 456 | if( addition > MAX_UNROLL_THRESHOLD ) 457 | Resample( samp, samp->sample_length + (4-(looplen & 7)) ); 458 | else 459 | Unroll_Sample_Loop( samp, count ); 460 | } 461 | } 462 | 463 | // Align loop_start 464 | if( samp->loop_type ) 465 | { 466 | int padsize; 467 | if( !(samp->format & SAMPF_COMP) ) 468 | { 469 | if( samp->format & SAMPF_16BIT ) { 470 | padsize = ( (2 - (samp->loop_start & 1)) & 1 ); 471 | } else { 472 | padsize = ( (4 - (samp->loop_start & 3)) & 3 ); 473 | } 474 | } 475 | else 476 | { 477 | padsize = ( (8 - (samp->loop_start & 7)) & 7 ); 478 | } 479 | Sample_PadStart( samp, padsize ); 480 | } 481 | 482 | // Pad end, only happens when loop is disabled 483 | if( !(samp->format & SAMPF_COMP) ) 484 | { 485 | if( samp->format & SAMPF_16BIT ) 486 | { 487 | if( samp->sample_length & 1 ) 488 | { 489 | Sample_PadEnd( samp, 2-(samp->sample_length&1) ); 490 | } 491 | } 492 | else 493 | { 494 | if( samp->sample_length & 3 ) 495 | { 496 | Sample_PadEnd( samp, 4-(samp->sample_length&3) ); 497 | } 498 | } 499 | } 500 | else 501 | { 502 | if( samp->sample_length & 7 ) 503 | { 504 | Sample_PadEnd( samp, 8-(samp->sample_length&7) ); 505 | } 506 | } 507 | 508 | Sample_Sign( samp ); // DS hardware takes signed samples 509 | 510 | if( samp->format & SAMPF_COMP ) 511 | { 512 | // compress with IMA-ADPCM hunger owned 513 | adpcm_compress_sample( samp ); 514 | } 515 | else 516 | { 517 | 518 | } 519 | } 520 | 521 | void FixSample( Sample* samp ) 522 | { 523 | // Clamp loop_start and loop_end (f.e. FR_TOWER.MOD) 524 | samp->loop_start = CLAMP(samp->loop_start, 0, samp->sample_length); 525 | samp->loop_end = CLAMP(samp->loop_end, 0, samp->sample_length); 526 | 527 | if( target_system == SYSTEM_GBA ) 528 | FixSample_GBA( samp ); 529 | else if( target_system == SYSTEM_NDS ) 530 | FixSample_NDS( samp ); 531 | } 532 | 533 | -------------------------------------------------------------------------------- /source/samplefix.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 24 | #include 25 | #include 26 | #include 27 | 28 | #include "defs.h" 29 | #include "mas.h" 30 | #include "simple.h" 31 | #include "files.h" 32 | #include "samplefix.h" 33 | 34 | // cREDITS TO CODA, LOOK AT THIS AWESOME CODES 35 | u32 readbits(u8* buffer, unsigned int pos, unsigned int size) { 36 | u32 result=0; 37 | u32 i; 38 | 39 | for(i=0;i>3; 43 | bit_pos = (pos+i)&7; 44 | result |= ( (buffer[byte_pos] >> bit_pos) & 1 ) << i; 45 | } 46 | return result; 47 | } 48 | 49 | int get_ext( char* filename ) 50 | { 51 | int strl = strlen(filename); 52 | int x; 53 | u32 a=0; 54 | if( strl < 4 ) 55 | return INPUT_TYPE_UNK; 56 | for( x = 0; x < 4; x++ ) 57 | { 58 | if( filename[strl-x-1] != '.' ) 59 | { 60 | a |= tolower(filename[strl-x-1]) << (x*8); 61 | } 62 | else 63 | break; 64 | } 65 | //a = tolower( filename[strl-1] ) | (tolower( filename[strl-1] )<<8) | tolower( filename[strl-2]<<16 ) | tolower( filename[strl-3]<<24 ); 66 | 67 | switch( a ) 68 | { 69 | case 'mod': 70 | return INPUT_TYPE_MOD; 71 | case 's3m': 72 | return INPUT_TYPE_S3M; 73 | case 'txt': 74 | return INPUT_TYPE_TXT; 75 | case 'wav': 76 | return INPUT_TYPE_WAV; 77 | case 'msl': 78 | return INPUT_TYPE_MSL; 79 | case 'xm': 80 | return INPUT_TYPE_XM; 81 | case 'it': 82 | return INPUT_TYPE_IT; 83 | case 'h': 84 | return INPUT_TYPE_H; 85 | } 86 | return INPUT_TYPE_UNK; 87 | } 88 | 89 | u32 calc_samplen_ex2( Sample* s ) 90 | { 91 | if( s->loop_type == 0 ) 92 | { 93 | return s->sample_length; 94 | } 95 | else 96 | { 97 | return s->loop_end; 98 | } 99 | } 100 | 101 | u32 calc_samplooplen( Sample* s ) 102 | { 103 | u32 a; 104 | if( s->loop_type == 1 ) 105 | { 106 | a = s->loop_end - s->loop_start; 107 | return a; 108 | } 109 | else if( s->loop_type == 2 ) 110 | { 111 | a = (s->loop_end-s->loop_start) *2; 112 | return a; 113 | } 114 | else 115 | { 116 | return 0xFFFFFFFF; 117 | } 118 | } 119 | 120 | u32 calc_samplen( Sample* s ) 121 | { 122 | if( s->loop_type == 1 ) 123 | { 124 | return s->loop_end; 125 | } 126 | else if( s->loop_type == 2 ) 127 | { 128 | return (s->loop_end-s->loop_start)+s->loop_end; 129 | } 130 | else 131 | { 132 | return s->sample_length; 133 | } 134 | } 135 | 136 | u8 sample_dsformat( Sample* samp ) 137 | { 138 | if( samp->format & SAMPF_COMP ) 139 | { 140 | return 2; 141 | } 142 | else 143 | { 144 | if( samp->format & SAMPF_SIGNED ) 145 | { 146 | if( samp->format & SAMPF_16BIT ) 147 | return 1; 148 | else 149 | return 0; 150 | } 151 | else 152 | { 153 | if( !(samp->format & SAMPF_16BIT) ) 154 | return 3; 155 | else 156 | return 3; // error 157 | } 158 | } 159 | } 160 | 161 | u8 sample_dsreptype( Sample* samp ) 162 | { 163 | if( samp->loop_type ) 164 | return 1; 165 | else 166 | return 2; 167 | } 168 | 169 | int clamp_s8( int value ) 170 | { 171 | if( value < -128 ) value = -128; 172 | if( value > 127 ) value = 127; 173 | return value; 174 | } 175 | 176 | int clamp_u8( int value ) 177 | { 178 | if( value < 0 ) value = 0; 179 | if( value > 255 ) value = 255; 180 | return value; 181 | } 182 | 183 | -------------------------------------------------------------------------------- /source/simple.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 26 | #include 27 | #include "defs.h" 28 | #include "files.h" 29 | #include "mas.h" 30 | #include "wav.h" 31 | #include "simple.h" 32 | #include "samplefix.h" 33 | 34 | int Load_WAV( Sample* samp, bool verbose, bool fix ) 35 | { 36 | unsigned int file_size; 37 | unsigned int bit_depth = 8; 38 | unsigned int hasformat = 0; 39 | unsigned int hasdata = 0; 40 | unsigned int chunk_code; 41 | unsigned int chunk_size; 42 | unsigned int num_channels = 0; 43 | unsigned int smpl_chunk_pos = 0; 44 | 45 | if( verbose ) 46 | printf( "Loading WAV file...\n" ); 47 | 48 | // initialize data 49 | memset( samp, 0, sizeof( Sample ) ); 50 | 51 | file_size = file_tell_size(); 52 | 53 | read32(); // "RIFF" 54 | read32(); // filesize-8 55 | read32(); // "WAVE" 56 | 57 | while( 1 ) 58 | { 59 | // break on end of file 60 | if( file_tell_read() >= file_size ) break; 61 | 62 | // read chunk code and length 63 | chunk_code = read32(); 64 | chunk_size = read32(); 65 | 66 | // parse chunk code 67 | switch( chunk_code ) 68 | { 69 | //--------------------------------------------------------------------- 70 | case ' tmf': // format chunk 71 | //--------------------------------------------------------------------- 72 | 73 | // check compression code (1 = PCM) 74 | if( read16() != 1 ) 75 | { 76 | if( verbose ) 77 | printf( "Unsupported WAV format.\n" ); 78 | return LOADWAV_UNKNOWN_COMP; 79 | } 80 | 81 | // read # of channels 82 | num_channels = read16(); 83 | 84 | // read sampling frequency 85 | samp->frequency = read32(); 86 | 87 | // skip average something, wBlockAlign 88 | read32(); 89 | read16(); 90 | 91 | // get bit depth, catch unsupported values 92 | bit_depth = read16(); 93 | if( bit_depth != 8 && bit_depth != 16 ) 94 | { 95 | if( verbose ) 96 | printf( "Unsupported bit-depth.\n" ); 97 | return LOADWAV_UNSUPPORTED_BD; 98 | } 99 | 100 | if( bit_depth == 16 ) 101 | samp->format |= SAMPF_16BIT; 102 | 103 | // print verbose data 104 | if( verbose ) 105 | { 106 | printf( "Sample Rate...%i\n", samp->frequency ); 107 | printf( "Bit Depth.....%i-bit\n", bit_depth ); 108 | } 109 | 110 | // skip the rest of the chunk (if any) 111 | if( (chunk_size - 0x10) > 0 ) 112 | skip8( (chunk_size - 0x10) ); 113 | 114 | hasformat = 1; 115 | break; 116 | 117 | //--------------------------------------------------------------------- 118 | case 'atad': // data chunk 119 | //--------------------------------------------------------------------- 120 | { 121 | int t, c, dat; 122 | 123 | if( !hasformat ) 124 | { 125 | return LOADWAV_CORRUPT; 126 | } 127 | 128 | if( verbose ) 129 | printf( "Loading Sample Data...\n" ); 130 | 131 | // clip chunk size against end of file (for some borked wavs...) 132 | { 133 | int br = file_size - file_tell_read(); 134 | chunk_size = chunk_size > br ? br : chunk_size; 135 | } 136 | 137 | samp->sample_length = chunk_size / (bit_depth/8) / num_channels; 138 | samp->data = malloc( chunk_size ); 139 | 140 | // read sample data 141 | for( t = 0; t < samp->sample_length; t++ ) 142 | { 143 | dat = 0; 144 | 145 | // for multi-channel samples, get average value 146 | for( c = 0; c < num_channels; c++ ) 147 | { 148 | dat += bit_depth == 8 ? ((int)read8()) - 128 : ((short)read16()); 149 | } 150 | dat /= num_channels; 151 | 152 | if( bit_depth == 8 ) 153 | { 154 | ((u8*)samp->data)[t] = dat + 128; 155 | } 156 | else 157 | { 158 | ((u16*)samp->data)[t] = dat + 32768; 159 | } 160 | } 161 | 162 | hasdata = 1; 163 | 164 | break; 165 | } 166 | //------------------------------------------------------------------------------ 167 | case 'lpms': // sampler chunk 168 | //------------------------------------------------------------------------------ 169 | { 170 | smpl_chunk_pos = file_tell_read(); 171 | skip8( chunk_size ); 172 | break; 173 | } 174 | default: 175 | skip8( chunk_size ); 176 | } 177 | } 178 | 179 | // sampler chunk is processed last because it depends on the sample length being known. 180 | if ( smpl_chunk_pos ) 181 | { 182 | file_seek_read( smpl_chunk_pos, SEEK_SET ); 183 | 184 | skip8( 4 // manufacturer 185 | +4 // product 186 | +4 // sample period 187 | +4 // midi unity note 188 | +4 // midi pitch fraction 189 | +4 // smpte format 190 | +4 // smpte offset 191 | ); 192 | 193 | int num_sample_loops = read32(); 194 | 195 | read32(); // sample data 196 | 197 | // check for sample looping data 198 | if( num_sample_loops ) 199 | { 200 | read32(); // cue point ID 201 | int loop_type = read32(); 202 | 203 | if( loop_type < 2 ) 204 | { 205 | // sample | internal 206 | // 0=forward | 1 207 | // 1=bidi | 2 208 | samp->loop_type = loop_type + 1; 209 | samp->loop_start = read32(); 210 | samp->loop_end = read32(); 211 | 212 | // clip loop start against sample length 213 | if( samp->loop_end > samp->sample_length ) { 214 | samp->loop_end = samp->sample_length; 215 | } 216 | 217 | // disable tiny loop 218 | // catch invalid loop 219 | if( (samp->loop_start > samp->sample_length) || 220 | (samp->loop_end - samp->loop_start < 16) ) { 221 | samp->loop_type = 0; 222 | samp->loop_start = 0; 223 | samp->loop_end = 0; 224 | } 225 | 226 | // ignore fractional 227 | // ignore play count 228 | } 229 | } 230 | } 231 | 232 | if( hasformat && hasdata ) 233 | { 234 | if( fix ) FixSample( samp ); 235 | return LOADWAV_OK; 236 | } 237 | else 238 | { 239 | return LOADWAV_CORRUPT; 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /source/wav.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ /> 26 | #include 27 | #include "defs.h" 28 | #include "mas.h" 29 | #include "xm.h" 30 | #include "files.h" 31 | #include "simple.h" 32 | #include "errors.h" 33 | #include "math.h" 34 | #include "samplefix.h" 35 | 36 | #define cho 64 37 | 38 | #ifdef SUPER_ASCII 39 | #define vstr_xm_samp " %2i │ %s%s │ %-22s │\n" 40 | #define vstr_xm_nosamp " -- │ -- │ %-22s │\n" 41 | #define vstr_xm_div "────────────────────────────────────────────\n" 42 | #define vstr_xm_patt " \x0e %2i " 43 | #define vstr_xm_samp_top "┌─────┬───────┬────────┬────────────────────────┐\n" 44 | #define vstr_xm_samp_header "│INDEX│SAMPLES│ENVELOPE│ NAME │\n" 45 | #define vstr_xm_samp_prefix "│%3i │" 46 | #define vstr_xm_samp_slice "├─────┼───────┼────────┼────────────────────────┤\n" 47 | #define vstr_xm_samp_bottom "└─────┴───────┴────────┴────────────────────────┘\n" 48 | #else 49 | #define vstr_xm_samp " %2i | %s%s | %-22s |\n" 50 | #define vstr_xm_nosamp " -- | -- | %-22s |\n" 51 | #define vstr_xm_div "--------------------------------------------\n" 52 | #define vstr_xm_patt " Pattern %2i " 53 | #define vstr_xm_samp_top ".-----------------------------------------------.\n" 54 | #define vstr_xm_samp_header "|INDEX|SAMPLES|ENVELOPE| NAME |\n" 55 | #define vstr_xm_samp_prefix "|%3i |" 56 | #define vstr_xm_samp_slice "|-----+-------+--------+------------------------|\n" 57 | #define vstr_xm_samp_bottom "`-----------------------------------------------'\n" 58 | #endif 59 | 60 | int Get_XM_Frequency( s8 relnote, s8 finetune ) 61 | { 62 | double rn=relnote; 63 | double ft=finetune; 64 | double middle_c; 65 | double freq; 66 | middle_c = 8363.0f; 67 | freq = middle_c * pow( 2.0, (1.0/12.0)*rn + (1.0/(12.0*128.0))*ft ); 68 | return (int)freq; 69 | } 70 | 71 | int Load_XM_Instrument( Instrument* inst, MAS_Module* mas, u8* p_nextsample, bool verbose ) 72 | { 73 | 74 | int inst_size; 75 | int nsamples; 76 | 77 | int ns; 78 | 79 | int samp_headstart; 80 | int samp_headsize; 81 | int inst_headstart; 82 | 83 | int sample_old; 84 | 85 | int x,y; 86 | u32 t; 87 | 88 | u8 vibtype; 89 | u8 vibsweep; 90 | u8 vibdepth; 91 | u8 vibrate; 92 | 93 | s8 finetune; 94 | s8 relnote; 95 | u8 loopbits; 96 | 97 | u8 volbits; 98 | u8 panbits; 99 | 100 | Sample* samp; 101 | 102 | ns = *p_nextsample; 103 | 104 | memset( inst, 0, sizeof( Instrument ) ); 105 | 106 | inst_headstart = file_tell_read(); 107 | inst_size = read32(); 108 | 109 | for( x = 0; x < 22; x++ ) 110 | inst->name[x] = read8(); // instrument name 111 | // if( verbose ) 112 | // printf( " Name=\"%s\"\n", inst->name ); 113 | // if( read8() != 0 ) 114 | // return ERR_UNKNOWNINST; 115 | read8(); // instrument type, SUPPOSED TO ALWAYS BE 0... 116 | nsamples = read16(); 117 | if( nsamples > 0 ) 118 | { 119 | samp_headsize = read32(); 120 | // read sample map 121 | for( x = 0; x < 96; x++ ) 122 | { 123 | inst->notemap[x+12] = ((read8()+ns+1)*256) | (x+12); 124 | } 125 | for( x=0; x < 12; x++ ) 126 | inst->notemap[x] =( inst->notemap[12]&0xFF00) | x; 127 | for( x=96;x<120;x++) 128 | inst->notemap[x] =( inst->notemap[12]&0xFF00) | x; 129 | for( x = 0; x < 12; x++ ) 130 | { 131 | inst->envelope_volume.node_x[x] = read16(); 132 | inst->envelope_volume.node_y[x] = (u8)read16(); 133 | } 134 | for( x = 0; x < 12; x++ ) 135 | { 136 | inst->envelope_pan.node_x[x] = read16(); 137 | inst->envelope_pan.node_y[x] = (u8)read16(); 138 | } 139 | inst->global_volume = 128; 140 | inst->envelope_volume.node_count = read8(); 141 | inst->envelope_pan.node_count = read8(); 142 | inst->envelope_volume.sus_start = inst->envelope_volume.sus_end = read8(); 143 | inst->envelope_volume.loop_start = read8(); 144 | inst->envelope_volume.loop_end = read8(); 145 | inst->envelope_pan.sus_start = inst->envelope_pan.sus_end = read8(); 146 | inst->envelope_pan.loop_start = read8(); 147 | inst->envelope_pan.loop_end = read8(); 148 | volbits = read8(); 149 | panbits = read8(); 150 | inst->env_flags = 0; 151 | if( volbits & 1 ) 152 | inst->env_flags |= 1|8; 153 | if( panbits & 1 ) 154 | inst->env_flags |= 2; 155 | 156 | if( !(volbits & 2) ) 157 | inst->envelope_volume.sus_start=inst->envelope_volume.sus_end=255; 158 | if( !(panbits & 2) ) 159 | inst->envelope_pan.sus_start=inst->envelope_pan.sus_end=255; 160 | 161 | if( !(volbits & 4) ) 162 | inst->envelope_volume.loop_start=inst->envelope_volume.loop_end=255; 163 | if( !(panbits & 4) ) 164 | inst->envelope_pan.loop_start=inst->envelope_pan.loop_end=255; 165 | 166 | vibtype=read8(); 167 | vibsweep=32768/(read8()+1); 168 | vibdepth=read8(); 169 | vibrate=read8(); 170 | inst->fadeout = read16()/32; // apply scalar!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 171 | file_seek_read( inst_headstart+inst_size, SEEK_SET ); 172 | 173 | /* if( verbose ) 174 | { 175 | if( volbits & 1 ) 176 | printf( " Has Volume Envelope\n" ); 177 | if( panbits & 1 ) 178 | printf( " Has Panning Envelope\n" ); 179 | if( nsamples != 1 ) 180 | printf( " Contains %i samples...\n", nsamples ); 181 | else 182 | printf( " Loading sample\n" ); 183 | } 184 | */ 185 | // read sample headers 186 | for( x = 0; x < nsamples; x++ ) 187 | { 188 | if( ns+x >= 256 ) 189 | return ERR_TOOMANYSAMPLES; 190 | samp_headstart = file_tell_read(); 191 | samp = &mas->samples[ns+x]; 192 | // if( verbose && nsamples != 1 ) 193 | // printf( " Loading sample %i...\n", x+1 ); 194 | memset( samp, 0, sizeof( Sample ) ); 195 | samp->msl_index = 0xFFFF; 196 | samp->sample_length = read32(); 197 | samp->loop_start = read32(); 198 | samp->loop_end = read32()+samp->loop_start; 199 | samp->default_volume = read8(); 200 | samp->global_volume = 64; 201 | 202 | samp->vibtype = vibtype; 203 | samp->vibdepth = vibdepth; 204 | samp->vibspeed = vibrate; 205 | samp->vibrate = vibsweep; 206 | 207 | finetune = (s8)read8(); 208 | loopbits = read8(); 209 | samp->default_panning = (read8()>>1) | 128; 210 | relnote = (s8)read8(); 211 | read8(); // reserved 212 | 213 | for( y =0; y <22; y ++) 214 | { 215 | samp->name[y] = read8(); 216 | if( y < 12 ) 217 | samp->filename[y] = samp->name[y]; 218 | } 219 | 220 | samp->frequency = Get_XM_Frequency( relnote, finetune ); 221 | 222 | // samp->bit16 = loopbits & 16 ? true : false; 223 | samp->format = loopbits & 16 ? SAMP_FORMAT_U16 : SAMP_FORMAT_U8; 224 | if( samp->format & SAMPF_16BIT ) 225 | { 226 | samp->sample_length /= 2; 227 | samp->loop_start /= 2; 228 | samp->loop_end /= 2; 229 | } 230 | samp->loop_type = loopbits & 3; 231 | file_seek_read( samp_headstart + samp_headsize, SEEK_SET ); 232 | /* 233 | if( verbose ) 234 | { 235 | printf( " Length........%i\n", samp->sample_length ); 236 | if( samp->loop_type == 0 ) 237 | printf( " Loop..........Disabled\n" ); 238 | else if( samp->loop_type == 1 ) 239 | printf( " Loop..........Forward %i->%i\n", samp->loop_start, samp->loop_end ); 240 | else if( samp->loop_type == 2 ) 241 | printf( " Loop..........BIDI %i->%i\n", samp->loop_start, samp->loop_end ); 242 | printf( " Volume........%i\n", samp->default_volume ); 243 | printf( " Panning.......%i\n", samp->default_panning & 127 ); 244 | printf( " Middle C......%ihz\n", samp->frequency ); 245 | printf( " 16 bit........%s\n", (samp->format & SAMPF_16BIT) ? "yes (will be converted)" : "no" ); 246 | }*/ 247 | } 248 | 249 | // read sample 250 | for( x = 0; x < nsamples; x++ ) 251 | { 252 | samp = &mas->samples[ns+x]; 253 | if( samp->sample_length == 0 ) 254 | continue; 255 | 256 | sample_old = 0; 257 | if( samp->format & SAMPF_16BIT ) 258 | { 259 | samp->data = (u16*)malloc( samp->sample_length*2 ); 260 | for( t = 0; t < samp->sample_length; t++ ) 261 | { 262 | sample_old = (s16)((s16)read16() + sample_old); 263 | ((u16*)samp->data)[t] = sample_old + 32768; 264 | } 265 | } 266 | else 267 | { 268 | samp->data = (u8*)malloc( samp->sample_length ); 269 | for( t = 0; t < samp->sample_length; t++ ) 270 | { 271 | sample_old = (s8)((s8)read8() + sample_old); 272 | ((u8*)samp->data)[t] = sample_old + 128; 273 | } 274 | } 275 | FixSample( samp ); 276 | } 277 | *p_nextsample = ns+nsamples; 278 | 279 | 280 | if( verbose ) 281 | { 282 | printf( vstr_xm_samp, nsamples, (volbits&1)?"V":"-", (panbits&1)?"P":"-", inst->name ); 283 | } 284 | } 285 | else 286 | { 287 | file_seek_read( inst_headstart+inst_size, SEEK_SET ); 288 | if( verbose ) 289 | printf( vstr_xm_nosamp, inst->name ); 290 | } 291 | 292 | return ERR_NONE; 293 | } 294 | 295 | void CONV_XM_EFFECT( u8* fx, u8* param ) 296 | { 297 | int wfx, wpm; 298 | wfx=*fx; 299 | wpm=*param; 300 | 301 | switch( wfx ) 302 | { 303 | case 0: // 0xy arpeggio 304 | if( wpm != 0) 305 | wfx = 'J'-cho; 306 | else 307 | wfx=wpm=0; 308 | break; 309 | 310 | case 1: // 1xx porta up 311 | wfx = 'F'-cho; 312 | if( wpm >= 0xE0 ) 313 | wpm = 0xDF; 314 | break; 315 | 316 | case 2: // 2xx porta down 317 | wfx = 'E'-cho; 318 | if( wpm >= 0xE0 ) 319 | wpm = 0xDF; 320 | break; 321 | 322 | case 3: // 3xx porta to note 323 | wfx = 'G'-cho; 324 | break; 325 | 326 | case 4: // 4xy vibrato 327 | wfx = 'H'-cho; 328 | break; 329 | 330 | case 5: // 5xy volslide+glissando 331 | wfx = 'L'-cho; 332 | break; 333 | 334 | case 6: // 6xy volslide+vibrato 335 | wfx = 'K'-cho; 336 | break; 337 | 338 | case 7: // 7xy tremolo 339 | wfx = 'R'-cho; 340 | break; 341 | 342 | case 8: // 8xx set panning 343 | wfx = 'X'-cho; 344 | break; 345 | 346 | case 9: // 9xx set offset 347 | wfx = 'O'-cho; 348 | break; 349 | 350 | case 0xA: // Axy volume slide 351 | wfx = 'D'-cho; 352 | break; 353 | 354 | case 0xB: // Bxx position jump 355 | wfx = 'B'-cho; 356 | break; 357 | 358 | case 0xC: // Cxx set volume 359 | wfx = 27; // compatibility effect 360 | break; 361 | 362 | case 0xD: // Dxx pattern break 363 | wfx = 'C'-cho; 364 | wpm = (wpm&0xF) + (wpm>>4) * 10; 365 | /*if( wpm >= 0xF0 ) what the fuck is this 366 | { 367 | wpm = 0xE0 | (wpm&0xF); 368 | } 369 | if( wpm & 0xF == 0xF ) 370 | { 371 | wpm = 0x0F | (wpm&0xF0); 372 | }*/ 373 | break; 374 | 375 | case 0xE: // Exy extended 376 | // if( (wpm & 0xF0) != 0xC0 ) 377 | // {int foo = 1;} 378 | switch( wpm >> 4 ) 379 | { 380 | case 1: // fine porta up 381 | wfx = 'F'-cho; 382 | wpm = 0xF0 | (wpm&0xF); 383 | break; 384 | 385 | case 2: // fine porta down 386 | wfx = 'E'-cho; 387 | wpm = 0xF0 | (wpm&0xF); 388 | break; 389 | 390 | case 3: // glissando control 391 | case 5: // set finetune 392 | // UNSUPPORTED :( 393 | wfx=0; 394 | wpm=0; 395 | break; 396 | 397 | case 4: // vibrato control 398 | wfx = 'S'-cho; 399 | wpm = 0x30 | (wpm&0xF); 400 | break; 401 | 402 | case 6: // pattern loop 403 | wfx = 'S'-cho; 404 | wpm = 0xB0 | (wpm&0xF); 405 | break; 406 | 407 | case 7: // tremolo control 408 | wfx = 'S'-cho; 409 | wpm = 0x40 | (wpm&0xF); 410 | break; 411 | 412 | case 8: // set panning 413 | wfx = 'X'-cho; 414 | wpm = (wpm&0xF) * 16; 415 | break; 416 | 417 | case 9: // old retrig 418 | wfx = 'S'-cho; 419 | wpm = 0x20 | (wpm&0xF); 420 | break; 421 | 422 | case 10: // fine volslide up 423 | wfx = 'S'-cho; 424 | wpm = 0x00 | (wpm&0xF); 425 | break; 426 | 427 | case 11: // fine volslide down 428 | wfx = 'S'-cho; 429 | wpm = 0x10 | (wpm&0xF); 430 | break; 431 | 432 | case 12: // note cut 433 | wfx = 'S'-cho; 434 | wpm = 0xC0 | (wpm&0xF); 435 | break; 436 | 437 | case 13: // note delay 438 | wfx = 'S'-cho; 439 | wpm = 0xD0 | (wpm&0xF); 440 | break; 441 | 442 | case 14: // pattern delay 443 | wfx = 'S'-cho; 444 | wpm = 0xE0 | (wpm&0xF); 445 | break; 446 | case 15: // event 447 | wfx = 'S'-cho; 448 | wpm = wpm; 449 | break; 450 | case 0: // set filter 451 | wfx=0; 452 | wpm=0; 453 | 454 | } 455 | break; 456 | 457 | case 0xF: // Fxx set speed 458 | if( wpm >= 32 ) 459 | wfx = 'T'-cho; 460 | else 461 | wfx = 'A'-cho; 462 | break; 463 | 464 | case 16: // Gxx set global volume 465 | wfx = 'V'-cho; 466 | wpm=wpm; 467 | break; 468 | 469 | case 17: // Hxx global volume slide 470 | wfx = 'W'-cho; 471 | break; 472 | 473 | case 18: // Ixx unused 474 | case 19: // Jxx unused 475 | case 22: // Mxx unused 476 | case 23: // Nxx unused 477 | case 24: // Oxx unused 478 | case 26: // Qxx unused 479 | case 28: // Sxx unused 480 | case 30: // Uxx unused 481 | case 31: // Vxx unused 482 | case 32: // Wxx unused 483 | case 34: // Yxx unused 484 | case 35: // Zxx unused 485 | wfx = 0; 486 | wpm = 0; 487 | break; 488 | 489 | case 20: // Kxx key off 490 | wfx = 28; 491 | break; 492 | 493 | case 21: // Lxx set envelope position 494 | wfx = 29; 495 | break; 496 | 497 | case 25: // Pxx panning slide 498 | wfx = 'P'-cho; 499 | break; 500 | 501 | 502 | 503 | case 27: // Rxx retrigger note 504 | wfx = 'Q'-cho; 505 | break; 506 | 507 | case 29: // Txx tremor 508 | wfx = 30; 509 | break; 510 | 511 | case 33: // Xxx extra fine slide 512 | if( (wpm>>4) == 1 ) 513 | { 514 | wfx = 'F'-cho; 515 | wpm = 0xE0 | (wpm & 0xF); 516 | } 517 | else if( (wpm>>4) == 2 ) 518 | { 519 | wfx = 'E'-cho; 520 | wpm = 0xE0 | (wpm & 0xF); 521 | } 522 | else 523 | { 524 | wfx=0; 525 | wpm=0; 526 | } 527 | break; 528 | } 529 | *fx = wfx; 530 | *param = wpm; 531 | } 532 | 533 | int Load_XM_Pattern( Pattern* patt, u32 nchannels, bool verbose ) 534 | { 535 | u32 headsize; 536 | u32 headstart; 537 | u16 clength; 538 | u16 row, col; 539 | u8 b; 540 | u32 e; 541 | u8 fx,param; 542 | 543 | headstart = file_tell_read(); 544 | headsize = read32(); 545 | 546 | if( read8() != 0 ) 547 | return ERR_UNKNOWNPATTERN; 548 | 549 | memset( patt, 0, sizeof( Pattern ) ); 550 | 551 | patt->nrows = read16(); 552 | clength = read16(); 553 | 554 | if( verbose ) 555 | printf( "- %i rows, %.2f KB\n", patt->nrows, (float)(clength)/1000 ); 556 | 557 | 558 | for( row = 0; row < patt->nrows*MAX_CHANNELS; row++ ) 559 | { 560 | patt->data[row].note = 250; 561 | patt->data[row].vol = 0; 562 | } 563 | 564 | file_seek_read( headstart+headsize, SEEK_SET ); 565 | 566 | if( clength == 0 ) 567 | { 568 | // pattern is empty 569 | return ERR_NONE; 570 | } 571 | 572 | // read pattern data 573 | for( row = 0; row < patt->nrows; row++ ) 574 | { 575 | for( col = 0; col < nchannels; col++ ) 576 | { 577 | e = row*MAX_CHANNELS+col; 578 | b = read8(); 579 | if( b & 128 ) // packed 580 | { 581 | if( b & 1 ) // bit 0 set: Note follows 582 | { 583 | patt->data[e].note = read8(); // (byte) Note (1-96, 1 = C-0) 584 | if( patt->data[e].note == 97 ) 585 | patt->data[e].note = 255; 586 | else 587 | patt->data[e].note += 12-1; 588 | } 589 | if( b & 2 ) // 1 set: Instrument follows 590 | { 591 | patt->data[e].inst = read8(); // (byte) Instrument (1-128) 592 | } 593 | if( b & 4 ) // 2 set: Volume column byte follows 594 | { 595 | patt->data[e].vol = read8(); // (byte) Volume column byte 596 | } 597 | if( b & 8 ) // 3 set: Effect type follows 598 | fx = read8(); // (byte) Effect type 599 | else 600 | fx=0; 601 | if( b & 16 ) // 4 set: Guess what! 602 | param=read8(); // (byte) Effect parameter 603 | else 604 | param=0; 605 | 606 | if( fx != 0 || param != 0 ) 607 | { 608 | CONV_XM_EFFECT( &fx, ¶m ); // convert effect 609 | patt->data[e].fx = fx; 610 | patt->data[e].param = param; 611 | } 612 | } 613 | else // unpacked 614 | { 615 | patt->data[e].note = b; // (byte) Note (1-96, 1 = C-0) 616 | if( patt->data[e].note == 97 ) 617 | patt->data[e].note = 255; 618 | else 619 | patt->data[e].note += 12-1; 620 | patt->data[e].inst = read8(); // (byte) Instrument (1-128) 621 | patt->data[e].vol = read8(); // (byte) Volume column byte (see below) 622 | fx = read8(); // (byte) Effect type 623 | param=read8(); // (byte) Effect parameter 624 | CONV_XM_EFFECT( &fx, ¶m ); // convert effect 625 | patt->data[e].fx = fx; 626 | patt->data[e].param = param; 627 | } 628 | } 629 | } 630 | return ERR_NONE; 631 | } 632 | 633 | int Load_XM( MAS_Module* mod, bool verbose ) 634 | { 635 | int x; 636 | u16 xm_version; 637 | u32 xm_headsize; 638 | u16 xm_nchannels; 639 | u8 next_sample; 640 | 641 | memset( mod, 0, sizeof( MAS_Module ) ); 642 | 643 | mod->old_effects=true; 644 | mod->xm_mode=true; 645 | mod->global_volume=64; 646 | mod->old_mode=false; 647 | 648 | if( read32() != 'etxE' || read32() != 'dedn' || read32() != 'doM ' || read32() != ':elu' || read8() != ' ' ) 649 | return ERR_INVALID_MODULE; 650 | for( x = 0; x < 20; x++ ) 651 | mod->title[x] = read8(); 652 | if( verbose ) 653 | { 654 | printf( vstr_xm_div ); 655 | printf( "Loading XM, \"%s\"\n", mod->title ); 656 | } 657 | if( read8() != 0x1a ) 658 | return ERR_INVALID_MODULE; 659 | skip8( 20 ); // tracker name 660 | xm_version = read16(); 661 | xm_headsize = read32(); 662 | mod->order_count = (u8)read16(); 663 | mod->restart_pos = (u8)read16(); 664 | xm_nchannels = read16(); 665 | mod->patt_count = (u8)read16(); 666 | mod->inst_count = (u8)read16(); 667 | mod->freq_mode = read16() & 1 ? true : false; // flags 668 | mod->initial_speed = (u8)read16(); 669 | mod->initial_tempo = (u8)read16(); 670 | 671 | if( verbose ) 672 | { 673 | printf( "Version....%i.%i\n", xm_version>>8 & 0xFF, xm_version & 0xFF ); 674 | printf( "Length.....%i\n", mod->order_count ); 675 | printf( "Restart....%i\n", mod->restart_pos ); 676 | printf( "Channels...%i\n", xm_nchannels ); 677 | printf( "#Patterns..%i\n", mod->patt_count ); 678 | printf( "#Instr.....%i\n", mod->inst_count ); 679 | printf( "Freq Mode..%s\n", mod->freq_mode ? "Linear" : "Amiga" ); 680 | printf( "Speed......%i\n", mod->initial_speed ); 681 | printf( "Tempo......%i\n", mod->initial_tempo ); 682 | } 683 | 684 | for( x = 0; x < 32; x++ ) 685 | { 686 | mod->channel_volume[x] = 64; 687 | mod->channel_panning[x] = 128; 688 | } 689 | if( verbose ) 690 | { 691 | printf( vstr_xm_div ); 692 | printf( "Reading sequence...\n" ); 693 | } 694 | for( x = 0; x < 200; x++ ) // read order table 695 | { 696 | if( x < mod->order_count ) 697 | mod->orders[x] = read8(); 698 | else 699 | { 700 | read8(); 701 | mod->orders[x] = 255; 702 | } 703 | } 704 | 705 | for( ; x < 256; x++ ) // skip 200->255 706 | read8(); 707 | file_seek_read( 60+xm_headsize, SEEK_SET ); // or maybe 60.. 708 | 709 | if( verbose ) 710 | { 711 | printf( vstr_xm_div ); 712 | printf( "Loading patterns...\n" ); 713 | printf( vstr_xm_div ); 714 | } 715 | 716 | mod->patterns = (Pattern*)malloc( mod->patt_count * sizeof( Pattern ) ); 717 | for( x = 0; x < mod->patt_count; x++ ) 718 | { 719 | if( verbose ) 720 | printf( vstr_xm_patt, x+1 ); 721 | Load_XM_Pattern( &mod->patterns[x], xm_nchannels, verbose ); 722 | } 723 | 724 | mod->instruments = (Instrument*)malloc( mod->inst_count * sizeof( Instrument ) ); 725 | mod->samples = (Sample*)malloc( 256 * sizeof( Sample ) ); 726 | next_sample=0; 727 | 728 | 729 | if( verbose ) 730 | { 731 | printf( vstr_xm_div ); 732 | printf( "Loading instruments...\n" ); 733 | printf( vstr_xm_samp_top ); 734 | printf( vstr_xm_samp_header ); 735 | printf( vstr_xm_samp_slice ); 736 | } 737 | 738 | for( x = 0; x < mod->inst_count; x++ ) 739 | { 740 | // if( verbose ) 741 | // printf( "Reading Instrument %i...\n", x+1 ); 742 | if( verbose ) 743 | printf( vstr_xm_samp_prefix, x+1 ); 744 | Load_XM_Instrument( &mod->instruments[x], mod, &next_sample, verbose ); 745 | } 746 | 747 | if( verbose ) 748 | { 749 | printf( vstr_xm_samp_bottom ); 750 | } 751 | 752 | mod->samp_count = next_sample; 753 | return ERR_NONE; 754 | } 755 | -------------------------------------------------------------------------------- /source/xm.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * __ * 3 | * ____ ___ ____ __ ______ ___ ____ ____/ / * 4 | * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * 5 | * / / / / / / /_/ />