summaryrefslogtreecommitdiff
path: root/modules/chibi/cp_loader_it_samples.cpp
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2016-10-14 19:14:40 +0200
committerRémi Verschelde <rverschelde@gmail.com>2016-10-15 12:20:53 +0200
commite6dc51a0f764dcd7cd07482c022c1e92e6a4da3d (patch)
tree4562ecd03b4d438cae0b179968f091130dadc14d /modules/chibi/cp_loader_it_samples.cpp
parentcbf52606f4928df46fc89d37d781bad782f0616e (diff)
chibi: Move to a module
Diffstat (limited to 'modules/chibi/cp_loader_it_samples.cpp')
-rw-r--r--modules/chibi/cp_loader_it_samples.cpp620
1 files changed, 620 insertions, 0 deletions
diff --git a/modules/chibi/cp_loader_it_samples.cpp b/modules/chibi/cp_loader_it_samples.cpp
new file mode 100644
index 0000000000..ced7252a6c
--- /dev/null
+++ b/modules/chibi/cp_loader_it_samples.cpp
@@ -0,0 +1,620 @@
+/*************************************************************************/
+/* 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;c<chans;c++) {
+
+ for (int i=0;i<p_sample_data.length;i++) {
+
+ ptr16[i*chans+c]=file->get_word();
+ }
+ }
+ } else {
+
+ for (int c=0;c<chans;c++) {
+
+ for (int i=0;i<p_sample_data.length;i++) {
+
+ ptr8[i*chans+c]=file->get_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;i<header.smpnum;i++) {
+
+ //seek to sample
+ file->seek(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<p_buffsize;i++)
+ dest_buffer[i]=0;
+
+
+ dest_position = dest_buffer;
+
+ it215=(header.cmwt==0x215);
+
+ /* now unpack data till the dest buffer is full */
+
+ while (p_buffsize) {
+ /* read a new block of compressed data and reset variables */
+ if ( read_IT_compressed_block(false) ) {
+ CP_PRINTERR("Out of memory decompressing IT CPSample");
+ return true;
+ }
+
+
+ block_length = (p_buffsize < 0x8000) ? p_buffsize : 0x8000;
+
+ block_position = 0;
+
+ bit_width = 9; /* start with width of 9 bits */
+
+ d1 = d2 = 0; /* reset integrator buffers */
+
+ /* now uncompress the data block */
+ while ( block_position < block_length ) {
+
+ aux_value = read_n_bits_from_IT_compressed_block(bit_width); /* read bits */
+
+ if ( bit_width < 7 ) { /* method 1 (1-6 bits) */
+
+ if ( aux_value == (1 << (bit_width - 1)) ) { /* check for "100..." */
+
+ aux_value = read_n_bits_from_IT_compressed_block(3) + 1; /* yes -> 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<p_buffsize;i++)
+ dest_buffer[i]=0;
+
+ dest_position = dest_buffer;
+
+ it215=(header.cmwt==0x215);
+
+
+ while (p_buffsize) {
+ /* read a new block of compressed data and reset variables */
+ if ( read_IT_compressed_block(true) ) {
+
+ return true;
+ }
+
+
+ block_length = (p_buffsize < 0x4000) ? p_buffsize : 0x4000;
+
+ block_position = 0;
+
+ bit_width = 17; /* start with width of 9 bits */
+
+ d1 = d2 = 0; /* reset integrator buffers */
+
+ while ( block_position < block_length ) {
+
+ aux_value = read_n_bits_from_IT_compressed_block(bit_width); /* read bits */
+
+ if ( bit_width < 7 ) { /* method 1 (1-6 bits) */
+
+ if ( (signed)aux_value == (1 << (bit_width - 1)) ) { /* check for "100..." */
+
+ aux_value = read_n_bits_from_IT_compressed_block(4) + 1; /* yes -> 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;
+
+}
+
+
+