/*************************************************************************/ /* cp_loader_it_samples.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ /* */ /* 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_it.h" #include "cp_sample.h" struct AuxSampleData { uint32_t fileofs; uint32_t c5spd; uint32_t length; uint32_t loop_begin; uint32_t loop_end; bool loop_enabled; bool pingpong_enabled; bool is16bit; bool stereo; bool exists; bool compressed; }; enum IT_Sample_Flags { IT_SAMPLE_EXISTS=1, IT_SAMPLE_16BITS=2, IT_SAMPLE_STEREO=4, IT_SAMPLE_COMPRESSED=8, IT_SAMPLE_LOOPED=16, IT_SAMPLE_SUSTAIN_LOOPED=32, IT_SAMPLE_LOOP_IS_PINGPONG=64, IT_SAMPLE_SUSTAIN_LOOP_IS_PINGPONG=128 }; CPLoader::Error CPLoader_IT::load_sample(CPSample *p_sample) { AuxSampleData aux_sample_data; char aux_header[4]; file->get_byte_array((uint8_t*)aux_header,4); if ( aux_header[0]!='I' || aux_header[1]!='M' || aux_header[2]!='P' || aux_header[3]!='S') { //CP_PRINTERR("IT CPLoader CPSample: Failed Identifier"); return FILE_UNRECOGNIZED; } // Ignore deprecated 8.3 filename for (int i=0;i<12;i++) file->get_byte(); file->get_byte(); //ignore zerobyte p_sample->set_global_volume( file->get_byte() ); /* SAMPLE FLAGS */ uint8_t flags=file->get_byte(); aux_sample_data.loop_enabled=flags&IT_SAMPLE_LOOPED; aux_sample_data.pingpong_enabled=flags&IT_SAMPLE_LOOP_IS_PINGPONG; aux_sample_data.is16bit=flags&IT_SAMPLE_16BITS; aux_sample_data.exists=flags&IT_SAMPLE_EXISTS; aux_sample_data.stereo=flags&IT_SAMPLE_STEREO; aux_sample_data.compressed=flags&IT_SAMPLE_COMPRESSED; p_sample->set_default_volume(file->get_byte()); /* SAMPLE NAME */ char aux_name[26]; file->get_byte_array((uint8_t*)aux_name,26); p_sample->set_name(aux_name); // ?? uint8_t convert_flag=file->get_byte(); // PAN uint8_t pan=file->get_byte(); p_sample->set_pan( pan&0x7F ); p_sample->set_pan_enabled( pan & 0x80 ); aux_sample_data.length=file->get_dword(); aux_sample_data.loop_begin= file->get_dword(); aux_sample_data.loop_end= file->get_dword(); aux_sample_data.c5spd=file->get_dword(); /*p_sample->data.set_sustain_loop_begin=*/file->get_dword(); /*p_sample->data.sustain_loop_end=*/file->get_dword(); aux_sample_data.fileofs=file->get_dword(); p_sample->set_vibrato_speed( file->get_byte() ); p_sample->set_vibrato_depth( file->get_byte() ); p_sample->set_vibrato_rate( file->get_byte() ); switch( file->get_byte() ) { /* Vibrato Wave: 0=sine, 1=rampdown, 2=square, 3=random */ case 0: p_sample->set_vibrato_type( CPSample::VIBRATO_SINE ); break; case 1: p_sample->set_vibrato_type( CPSample::VIBRATO_SAW ); break; case 2: p_sample->set_vibrato_type( CPSample::VIBRATO_SQUARE ); break; case 3: p_sample->set_vibrato_type( CPSample::VIBRATO_RANDOM ); break; default: p_sample->set_vibrato_type( CPSample::VIBRATO_SINE ); break; } //printf("Name %s - Flags: fileofs :%i - c5spd %i - len %i 16b %i - data?: %i\n",p_sample->get_name(),aux_sample_data.fileofs,aux_sample_data.c5spd, aux_sample_data.length, aux_sample_data.is16bit,aux_sample_data.exists); CPSample_ID samp_id; if (aux_sample_data.exists) { samp_id=load_sample_data(aux_sample_data); CPSampleManager::get_singleton()->set_c5_freq(samp_id,aux_sample_data.c5spd); CPSampleManager::get_singleton()->set_loop_begin( samp_id,aux_sample_data.loop_begin ); CPSampleManager::get_singleton()->set_loop_end( samp_id,aux_sample_data.loop_end ); CPSample_Loop_Type loop_type=aux_sample_data.loop_enabled?( aux_sample_data.pingpong_enabled? CP_LOOP_BIDI: CP_LOOP_FORWARD):CP_LOOP_NONE; CPSampleManager::get_singleton()->set_loop_end( samp_id,aux_sample_data.loop_end ); CPSampleManager::get_singleton()->set_loop_type( samp_id, loop_type); } //printf("Loaded id is null?: %i\n",samp_id.is_null()); p_sample->set_sample_data(samp_id); if (!samp_id.is_null()) { // printf("Loaded ID: stereo: %i len %i 16bit %i\n",CPSampleManager::get_singleton()->is_stereo(samp_id), CPSampleManager::get_singleton()->get_size( samp_id), CPSampleManager::get_singleton()->is_16bits( samp_id) ); } CP_ERR_COND_V( file->eof_reached(),FILE_CORRUPTED ); CP_ERR_COND_V( file->get_error(),FILE_CORRUPTED ); return FILE_OK; } CPSample_ID CPLoader_IT::load_sample_data(AuxSampleData& p_sample_data) { int aux_sample_properties = (p_sample_data.is16bit?IT_SAMPLE_16BITS:0)|(p_sample_data.compressed?IT_SAMPLE_COMPRESSED:0)|(p_sample_data.stereo?IT_SAMPLE_STEREO:0); file->seek(p_sample_data.fileofs); CPSampleManager *sm=CPSampleManager::get_singleton(); CPSample_ID id; switch (aux_sample_properties) { case (0): // 8 bits, mono case (IT_SAMPLE_16BITS): // 16 bits mono case (IT_SAMPLE_STEREO): // 8 bits stereo case (IT_SAMPLE_16BITS|IT_SAMPLE_STEREO): { // 16 bits mono id=sm->create(p_sample_data.is16bit,p_sample_data.stereo,p_sample_data.length); if (id.is_null()) break; sm->lock_data(id); int16_t *ptr16 = (int16_t*)sm->get_data(id); int8_t *ptr8=(int8_t*)ptr16; int chans=p_sample_data.stereo?2:1; if (p_sample_data.is16bit) { for (int c=0;cget_word(); } } } else { for (int c=0;cget_byte(); } } } sm->unlock_data(id); } break; case (IT_SAMPLE_COMPRESSED): { // 8 bits compressed id=sm->create(false,false,p_sample_data.length); if (id.is_null()) break; sm->lock_data(id); if ( load_sample_8bits_IT_compressed((void*)sm->get_data( id),p_sample_data.length) ) { sm->unlock_data(id); sm->destroy(id); break; } sm->unlock_data(id); } break; case (IT_SAMPLE_16BITS|IT_SAMPLE_COMPRESSED): { // 16 bits compressed id=sm->create(true,false,p_sample_data.length); if (id.is_null()) break; sm->lock_data(id); if ( load_sample_16bits_IT_compressed((void*)sm->get_data(id),p_sample_data.length) ) { sm->unlock_data(id); sm->destroy(id); break; } sm->unlock_data(id); } break; default: { // I dont know how to handle stereo compressed, does that exist? } break; } return id; } CPLoader::Error CPLoader_IT::load_samples() { for (int i=0;iseek(0xC0+header.ordnum+header.insnum*4+i*4); uint32_t final_location=file->get_dword(); file->seek( final_location ); Error err=load_sample(song->get_sample(i)); CP_ERR_COND_V(err,err); } if (file->eof_reached() || file->get_error()) return FILE_CORRUPTED; return FILE_OK; } /* * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE -The following sample decompression code is based on xmp's code.(http://xmp.helllabs.org) which is based in openCP code. * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE */ uint32_t CPLoader_IT::read_n_bits_from_IT_compressed_block (uint8_t p_bits_to_read) { uint32_t aux_return_value; uint32_t val; uint8_t *buffer=(uint8_t*)source_position; if ( p_bits_to_read <= source_remaining_bits ) { val=buffer[3]; val<<=8; val|=buffer[2]; val<<=8; val|=buffer[1]; val<<=8; val|=buffer[0]; aux_return_value = val & ((1 << p_bits_to_read) - 1); val >>= p_bits_to_read; source_remaining_bits -= p_bits_to_read; buffer[3]=val>>24; buffer[2]=(val>>16)&0xFF; buffer[1]=(val>>8)&0xFF; buffer[0]=(val)&0xFF; } else { aux_return_value=buffer[3]; aux_return_value<<=8; aux_return_value|=buffer[2]; aux_return_value<<=8; aux_return_value|=buffer[1]; aux_return_value<<=8; aux_return_value|=buffer[0]; uint32_t nbits = p_bits_to_read - source_remaining_bits; source_position++; buffer+=4; val=buffer[3]; val<<=8; val|=buffer[2]; val<<=8; val|=buffer[1]; val<<=8; val|=buffer[0]; aux_return_value |= ((val & ((1 << nbits) - 1)) << source_remaining_bits); val >>= nbits; source_remaining_bits = 32 - nbits; buffer[3]=val>>24; buffer[2]=(val>>16)&0xFF; buffer[1]=(val>>8)&0xFF; buffer[0]=(val)&0xFF; } return aux_return_value; } bool CPLoader_IT::read_IT_compressed_block (bool p_16bits) { uint16_t size; size=file->get_word(); if (file->eof_reached() || file->get_error()) return true; pat_data = (uint8_t*)CP_ALLOC( 4* ((size >> 2) + 2) ); if (!pat_data) return true; source_buffer=(uint32_t*)pat_data; file->get_byte_array((uint8_t*)source_buffer,size); if (file->eof_reached() || file->get_error()) { free_IT_compressed_block(); return true; } source_position = source_buffer; source_remaining_bits = 32; return false; } void CPLoader_IT::free_IT_compressed_block () { if (pat_data) { CP_FREE(pat_data); pat_data=NULL; } } bool CPLoader_IT::load_sample_8bits_IT_compressed(void *p_dest_buffer,int p_buffsize) { int8_t *dest_buffer; /* destination buffer which will be returned */ uint16_t block_length; /* length of compressed data block in samples */ uint16_t block_position; /* position in block */ uint8_t bit_width; /* actual "bit width" */ uint16_t aux_value; /* value read from file to be processed */ int8_t d1, d2; /* integrator buffers (d2 for it2.15) */ int8_t *dest_position; /* position in output buffer */ int8_t v; /* sample value */ bool it215; // is this an it215 module? dest_buffer = (int8_t *) p_dest_buffer; if (dest_buffer==NULL) return true; for (int i=0;i read new width; */ bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; /* and expand it */ continue; /* ... next value */ } } else if ( bit_width < 9 ) { /* method 2 (7-8 bits) */ uint8_t border = (0xFF >> (9 - bit_width)) - 4; /* lower border for width chg */ if ( aux_value > border && aux_value <= (border + 8) ) { aux_value -= border; /* convert width to 1-8 */ bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; /* and expand it */ continue; /* ... next value */ } } else if ( bit_width == 9 ) { /* method 3 (9 bits) */ if ( aux_value & 0x100 ) { /* bit 8 set? */ bit_width = (aux_value + 1) & 0xff; /* new width... */ continue; /* ... and next value */ } } else { /* illegal width, abort */ free_IT_compressed_block(); CP_PRINTERR("CPSample has illegal BitWidth "); return true; } /* now expand value to signed byte */ if ( bit_width < 8 ) { uint8_t tmp_shift = 8 - bit_width; v=(aux_value << tmp_shift); v>>=tmp_shift; } else v = (int8_t) aux_value; /* integrate upon the sample values */ d1 += v; d2 += d1; /* ... and store it into the buffer */ *(dest_position++) = it215 ? d2 : d1; block_position++; } /* now subtract block lenght from total length and go on */ free_IT_compressed_block(); p_buffsize -= block_length; } return false; } bool CPLoader_IT::load_sample_16bits_IT_compressed(void *p_dest_buffer,int p_buffsize) { int16_t *dest_buffer; /* destination buffer which will be returned */ uint16_t block_length; /* length of compressed data block in samples */ uint16_t block_position; /* position in block */ uint8_t bit_width; /* actual "bit width" */ uint32_t aux_value; /* value read from file to be processed */ int16_t d1, d2; /* integrator buffers (d2 for it2.15) */ int16_t *dest_position; /* position in output buffer */ int16_t v; /* sample value */ bool it215; // is this an it215 module? dest_buffer = (int16_t *) p_dest_buffer; if (dest_buffer==NULL) return true; for (int i=0;i read new width; */ bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; /* and expand it */ continue; /* ... next value */ } } else if ( bit_width < 17 ) { uint16_t border = (0xFFFF >> (17 - bit_width)) - 8; if ( (int)aux_value > (int)border && (int)aux_value <= ((int)border + 16) ) { aux_value -= border; /* convert width to 1-8 */ bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; /* and expand it */ continue; /* ... next value */ } } else if ( bit_width == 17 ) { if ( aux_value & 0x10000 ) { /* bit 8 set? */ bit_width = (aux_value + 1) & 0xff; /* new width... */ continue; /* ... and next value */ } } else { /* illegal width, abort */ CP_PRINTERR("CPSample has illegal BitWidth "); free_IT_compressed_block(); return true; } /* now expand value to signed byte */ if ( bit_width < 16 ) { uint8_t tmp_shift = 16 - bit_width; v=(aux_value << tmp_shift); v>>=tmp_shift; } else v = (int16_t) aux_value; /* integrate upon the sample values */ d1 += v; d2 += d1; /* ... and store it into the buffer */ *(dest_position++) = it215 ? d2 : d1; block_position++; } /* now subtract block lenght from total length and go on */ free_IT_compressed_block(); p_buffsize -= block_length; } return false; }