2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* cp_loader_s3m.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
2017-01-01 22:01:57 +01:00
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
2014-02-10 02:10:30 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
# include "cp_loader_s3m.h"
2017-03-19 00:36:26 +01:00
# define BITBOOL(m_exp) ((m_exp) ? 1 : 0)
2014-02-10 02:10:30 +01:00
CPLoader : : Error CPLoader_S3M : : load_header ( ) {
int i ;
2017-03-19 00:36:26 +01:00
file - > get_byte_array ( ( uint8_t * ) header . songname , 28 ) ;
header . t1a = file - > get_byte ( ) ;
header . type = file - > get_byte ( ) ;
file - > get_byte_array ( ( uint8_t * ) header . unused1 , 2 ) ;
header . ordnum = file - > get_word ( ) ;
header . insnum = file - > get_word ( ) ;
header . patnum = file - > get_word ( ) ;
header . flags = file - > get_word ( ) ;
header . tracker = file - > get_word ( ) ;
header . fileformat = file - > get_word ( ) ;
file - > get_byte_array ( ( uint8_t * ) header . scrm , 4 ) ;
header . scrm [ 4 ] = 0 ;
if ( header . scrm [ 0 ] ! = ' S ' | | header . scrm [ 1 ] ! = ' C ' | | header . scrm [ 2 ] ! = ' R ' | | header . scrm [ 3 ] ! = ' M ' )
2014-02-10 02:10:30 +01:00
return FILE_UNRECOGNIZED ;
2017-03-19 00:36:26 +01:00
header . mastervol = file - > get_byte ( ) ;
header . initspeed = file - > get_byte ( ) ;
header . inittempo = file - > get_byte ( ) ;
header . mastermult = file - > get_byte ( ) ;
header . ultraclick = file - > get_byte ( ) ;
header . pantable = file - > get_byte ( ) ;
file - > get_byte_array ( ( uint8_t * ) header . unused2 , 8 ) ;
header . special = file - > get_word ( ) ;
file - > get_byte_array ( ( uint8_t * ) header . channels , 32 ) ;
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
file - > get_byte_array ( ( uint8_t * ) header . orderlist , header . ordnum ) ;
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
header . scrm [ 4 ] = 0 ;
if ( header . scrm [ 0 ] ! = ' S ' | | header . scrm [ 1 ] ! = ' C ' | | header . scrm [ 2 ] ! = ' R ' | | header . scrm [ 3 ] ! = ' M ' ) //again?
2014-02-10 02:10:30 +01:00
return FILE_UNRECOGNIZED ;
//sample parapointers
2017-03-19 00:36:26 +01:00
for ( i = 0 ; i < header . insnum ; i + + ) {
2014-02-10 02:10:30 +01:00
int parapointer ;
2017-03-19 00:36:26 +01:00
parapointer = file - > get_word ( ) ;
parapointer = ( parapointer * 16 ) ;
sample_parapointers [ i ] = parapointer ;
2014-02-10 02:10:30 +01:00
}
//pattern
2017-03-19 00:36:26 +01:00
for ( i = 0 ; i < header . patnum ; i + + ) {
2014-02-10 02:10:30 +01:00
int parapointer ;
2017-03-19 00:36:26 +01:00
parapointer = file - > get_word ( ) ;
parapointer = ( parapointer * 16 ) ;
pattern_parapointers [ i ] = parapointer ;
2014-02-10 02:10:30 +01:00
}
2017-03-19 00:36:26 +01:00
if ( header . pantable = = 252 ) {
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
file - > get_byte_array ( ( uint8_t * ) header . pannings , 32 ) ;
2014-02-10 02:10:30 +01:00
}
return FILE_OK ;
}
void CPLoader_S3M : : set_header ( ) {
2017-03-19 00:36:26 +01:00
song - > set_name ( header . songname ) ;
// song->variables.filename=
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
song - > set_row_highlight_minor ( 4 ) ;
song - > set_row_highlight_major ( 16 ) ;
song - > set_mixing_volume ( header . mastervol ) ;
song - > set_linear_slides ( false ) ;
song - > set_old_effects ( ! ( header . flags & 64 ) ) ;
song - > set_compatible_gxx ( true ) ;
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
song - > set_global_volume ( header . mastermult ) ;
song - > set_speed ( header . initspeed ) ;
song - > set_tempo ( header . inittempo ) ;
2014-02-10 02:10:30 +01:00
//[TODO] Set Panning Positions.. ?
2017-03-19 00:36:26 +01:00
for ( int i = 0 ; i < header . ordnum ; i + + )
song - > set_order ( i , header . orderlist [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-19 00:36:26 +01:00
CPLoader : : Error CPLoader_S3M : : load_sample ( CPSample * p_sample ) {
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
int type = file - > get_byte ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
char filename [ 13 ] ;
file - > get_byte_array ( ( uint8_t * ) filename , 12 ) ;
filename [ 12 ] = 0 ;
2015-12-29 20:06:45 +01:00
2017-03-19 00:36:26 +01:00
uint32_t samplepos = ( uint32_t ) file - > get_byte ( ) < < 16 ;
samplepos | = file - > get_word ( ) ;
samplepos * = 16 ;
// printf("sample at %i\n",samplepos);
/**/
int sample_size = file - > get_dword ( ) ;
2015-12-29 20:06:45 +01:00
2017-03-19 00:36:26 +01:00
int loop_begin = file - > get_dword ( ) ;
int loop_end = file - > get_dword ( ) ;
int def_volume = file - > get_byte ( ) ;
;
int dsk = file - > get_byte ( ) ;
int pack = file - > get_byte ( ) ;
int flags = file - > get_byte ( ) ;
int c2speed = file - > get_dword ( ) ;
file - > get_dword ( ) ; //useless crap
file - > get_dword ( ) ;
file - > get_dword ( ) ;
char name [ 29 ] ;
file - > get_byte_array ( ( uint8_t * ) name , 28 ) ;
name [ 28 ] = 0 ;
p_sample - > set_default_volume ( def_volume ) ;
p_sample - > set_name ( name ) ;
char scrs [ 5 ] ;
file - > get_byte_array ( ( uint8_t * ) scrs , 4 ) ;
scrs [ 4 ] = 0 ;
bool data_is_16bits = flags & 4 ;
bool data_is_stereo = flags & 2 ;
2015-12-29 20:06:45 +01:00
2017-03-19 00:36:26 +01:00
if ( type = = 0 ) {
//empty sample
return FILE_OK ;
}
if ( ( type ! = 1 ) | | scrs [ 0 ] ! = ' S ' | | scrs [ 1 ] ! = ' C ' | | scrs [ 2 ] ! = ' R ' | | scrs [ 3 ] ! = ' S ' ) {
// printf("type: %i, %c%c%c%c\n",type,scrs[0],scrs[1],scrs[2],scrs[3]);
CP_PRINTERR ( " Not an S3M CPSample! " ) ;
return FILE_CORRUPTED ;
}
//p_sample->data.set_c5_freq(p_sample->c2spd<<1);
file - > seek ( samplepos ) ;
int real_sample_size = sample_size < < BITBOOL ( data_is_16bits ) ;
real_sample_size < < = BITBOOL ( data_is_stereo ) ;
CPSampleManager * sm = CPSampleManager : : get_singleton ( ) ;
CPSample_ID id = sm - > create ( data_is_16bits , data_is_stereo , sample_size ) ;
if ( id . is_null ( ) )
return FILE_OUT_OF_MEMORY ;
sm - > lock_data ( id ) ;
void * dataptr = sm - > get_data ( id ) ;
int chans = ( data_is_stereo ? 2 : 1 ) ;
for ( int c = 0 ; c < chans ; c + + ) {
for ( int i = 0 ; i < sample_size ; i + + ) {
if ( data_is_16bits ) {
uint16_t s = file - > get_word ( ) ;
s - = 32768 ; //toggle sign
int16_t * v = ( int16_t * ) & s ;
( ( int16_t * ) dataptr ) [ i * chans + c ] = * v ;
} else {
int8_t * v ;
uint8_t s = file - > get_byte ( ) ;
s - = 128 ; //toggle sign
v = ( int8_t * ) & s ;
( ( int8_t * ) dataptr ) [ i * chans + c ] = * v ;
2014-02-10 02:10:30 +01:00
}
}
2017-03-19 00:36:26 +01:00
}
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
sm - > unlock_data ( id ) ;
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
sm - > set_loop_begin ( id , loop_begin ) ;
sm - > set_loop_end ( id , loop_end ) ;
sm - > set_loop_type ( id , ( flags & 1 ) ? CP_LOOP_FORWARD : CP_LOOP_NONE ) ;
sm - > set_c5_freq ( id , c2speed < < 1 ) ;
p_sample - > set_sample_data ( id ) ;
/* Scream tracker previous to 3.10 seems to be buggy, as in, wont save what is after the sample loop, including the loop end point. Because of this I must fix it by habd */
if ( flags & 1 ) {
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
for ( int c = 0 ; c < ( data_is_stereo ? 2 : 1 ) ; c + + ) {
sm - > set_data ( id , loop_end , sm - > get_data ( id , loop_begin , c ) , c ) ;
}
}
return FILE_OK ;
}
2014-02-10 02:10:30 +01:00
CPLoader : : Error CPLoader_S3M : : load_pattern ( CPPattern * p_pattern ) {
2017-03-19 00:36:26 +01:00
int row = 0 , flag , ch ;
2014-02-10 02:10:30 +01:00
CPNote n ;
2017-03-19 00:36:26 +01:00
int length , accum = 0 ;
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
length = file - > get_word ( ) ;
p_pattern - > set_length ( 64 ) ;
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
/* clear pattern data */
while ( ( row < 64 ) & & ( accum < = length ) ) {
flag = file - > get_byte ( ) ;
2014-02-10 02:10:30 +01:00
accum + + ;
n . clear ( ) ;
2017-03-19 00:36:26 +01:00
if ( flag ) {
// ch=remap[flag&31];
// ch=remap[flag&31];
// if(ch!=-1)
// n=s3mbuf[(64U*ch)+row];
// else
// n=&dummy;
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
ch = flag & 31 ;
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
if ( flag & 32 ) {
n . note = file - > get_byte ( ) ;
if ( n . note = = 255 ) {
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
n . note = CPNote : : EMPTY ;
} else if ( n . note = = 254 ) {
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
n . note = CPNote : : CUT ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-19 00:36:26 +01:00
n . note = ( ( n . note > > 4 ) * 12 ) + ( n . note & 0xF ) ;
}
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
n . instrument = file - > get_byte ( ) - 1 ;
accum + = 2 ;
}
if ( flag & 64 ) {
n . volume = file - > get_byte ( ) ;
if ( n . volume > 64 ) n . volume = 64 ;
2014-02-10 02:10:30 +01:00
accum + + ;
2017-03-19 00:36:26 +01:00
}
if ( flag & 128 ) {
n . command = file - > get_byte ( ) - 1 ;
n . parameter = file - > get_byte ( ) ;
accum + = 2 ;
}
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
p_pattern - > set_note ( ch , row , n ) ;
} else
row + + ;
}
return FILE_OK ;
2014-02-10 02:10:30 +01:00
}
2017-03-19 00:36:26 +01:00
CPLoader : : Error CPLoader_S3M : : load_sample ( const char * p_file , CPSample * p_sample ) {
2014-02-10 02:10:30 +01:00
return FILE_UNRECOGNIZED ;
}
2017-03-19 00:36:26 +01:00
CPLoader : : Error CPLoader_S3M : : load_instrument ( const char * p_file , CPSong * p_song , int p_instr_idx ) {
2014-02-10 02:10:30 +01:00
return FILE_UNRECOGNIZED ;
}
CPLoader : : Error CPLoader_S3M : : load_samples ( ) {
int i ;
2017-03-19 00:36:26 +01:00
for ( i = 0 ; i < header . insnum ; i + + ) {
2014-02-10 02:10:30 +01:00
file - > seek ( sample_parapointers [ i ] ) ;
load_sample ( song - > get_sample ( i ) ) ;
sample_count + + ;
}
return FILE_OK ;
}
CPLoader : : Error CPLoader_S3M : : load_patterns ( ) {
int i ;
Error err ;
2017-03-19 00:36:26 +01:00
for ( i = 0 ; i < header . patnum ; i + + ) {
2014-02-10 02:10:30 +01:00
file - > seek ( pattern_parapointers [ i ] ) ;
2017-03-19 00:36:26 +01:00
err = load_pattern ( song - > get_pattern ( i ) ) ;
CP_ERR_COND_V ( err , err ) ;
2014-02-10 02:10:30 +01:00
pattern_count + + ;
}
return FILE_OK ;
}
2017-03-19 00:36:26 +01:00
CPLoader : : Error CPLoader_S3M : : load_song ( const char * p_file , CPSong * p_song , bool p_sampleset ) {
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
song = p_song ;
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
if ( file - > open ( p_file , CPFileAccessWrapper : : READ ) ) {
2014-02-10 02:10:30 +01:00
//printf("Can't open file! %s\n",p_file);
return FILE_CANNOT_OPEN ;
} ;
2017-03-19 00:36:26 +01:00
sample_count = 0 ;
pattern_count = 0 ;
2014-02-10 02:10:30 +01:00
//printf("LOADING HEADER\n");
CPLoader : : Error err ;
2017-03-19 00:36:26 +01:00
if ( ( err = load_header ( ) ) ) {
2014-02-10 02:10:30 +01:00
file - > close ( ) ;
2017-03-19 00:36:26 +01:00
CP_ERR_COND_V ( err , err ) ;
}
2014-02-10 02:10:30 +01:00
song - > reset ( ) ; //file type recognized, reset song!
2017-03-19 00:36:26 +01:00
2014-02-10 02:10:30 +01:00
set_header ( ) ;
2017-03-19 00:36:26 +01:00
2014-02-10 02:10:30 +01:00
//printf("LOADING SAMPLES\n");
2017-03-19 00:36:26 +01:00
if ( ( err = load_samples ( ) ) ) {
2014-02-10 02:10:30 +01:00
file - > close ( ) ;
2017-03-19 00:36:26 +01:00
CP_ERR_COND_V ( err , err ) ;
}
2014-02-10 02:10:30 +01:00
//printf("LOADING PATTERNS\n");
2017-03-19 00:36:26 +01:00
if ( ( err = load_patterns ( ) ) ) {
2014-02-10 02:10:30 +01:00
file - > close ( ) ;
return err ;
2017-03-19 00:36:26 +01:00
}
2014-02-10 02:10:30 +01:00
file - > close ( ) ;
return FILE_OK ;
}
2017-03-19 00:36:26 +01:00
CPLoader_S3M : : CPLoader_S3M ( CPFileAccessWrapper * p_file ) {
2014-02-10 02:10:30 +01:00
2017-03-19 00:36:26 +01:00
file = p_file ;
2014-02-10 02:10:30 +01:00
}
2017-03-19 00:36:26 +01:00
CPLoader_S3M : : ~ CPLoader_S3M ( ) {
2014-02-10 02:10:30 +01:00
}