mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2025-02-24 20:31:39 +00:00
825 lines
21 KiB
C++
825 lines
21 KiB
C++
|
#ifdef FORTIFY
|
||
|
#include "fortify.h"
|
||
|
#endif
|
||
|
#include <stdio.h>
|
||
|
#ifdef MSS
|
||
|
#include "mss.h"
|
||
|
#endif
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "allegro.h"
|
||
|
#include "modulus.h"
|
||
|
#include "typedef.hpp"
|
||
|
|
||
|
int detect_it(char *f) {
|
||
|
int sig;
|
||
|
PACKFILE *fn = pack_fopen(f, "rb");
|
||
|
|
||
|
if (fn == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
sig = pack_mgetl(fn);
|
||
|
if (sig != AL_ID('I','M','P','M')) {
|
||
|
pack_fclose(fn);
|
||
|
return FALSE;
|
||
|
}
|
||
|
pack_fclose(fn);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
MODULUS *create_it() {
|
||
|
MODULUS *m = (MODULUS*)malloc(sizeof(MODULUS));
|
||
|
if (!m)
|
||
|
return NULL;
|
||
|
memset(m, 0, sizeof(MODULUS));
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
void destroy_it(MODULUS *j) {
|
||
|
|
||
|
if (song->Music == j)
|
||
|
stop_it();
|
||
|
|
||
|
//remove patterns:
|
||
|
for (int i=0; i<j->NumPatterns; i++) {
|
||
|
free(j->Pattern[i].Note);
|
||
|
}
|
||
|
if (j->Pattern)
|
||
|
free(j->Pattern);
|
||
|
//remove instruments;
|
||
|
if (j->Instrument)
|
||
|
free(j->Instrument);
|
||
|
//remove samples;
|
||
|
for (int i=0; i<j->NumSamples; i++) {
|
||
|
destroy_sample(j->Sample[i].Sample);
|
||
|
}
|
||
|
if (j->Sample)
|
||
|
free(j->Sample);
|
||
|
//remove orders:
|
||
|
if (j->Order)
|
||
|
free(j->Order);
|
||
|
//remove channels:
|
||
|
for (int i=0; i<64; i++) {
|
||
|
if (j->Channel[i].VChannel) {
|
||
|
MODULUS_VCHANNEL *vchn = song->Music->Channel[i].VChannel;
|
||
|
MODULUS_VCHANNEL *prev = NULL;
|
||
|
|
||
|
if (!vchn)
|
||
|
continue;
|
||
|
|
||
|
for (;;) {
|
||
|
deallocate_voice(vchn->voice);
|
||
|
|
||
|
prev = vchn;
|
||
|
vchn = vchn->next;
|
||
|
free(prev);
|
||
|
|
||
|
if (!vchn)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
free(j);
|
||
|
}
|
||
|
|
||
|
//#define DEBUG_IT_SIZE
|
||
|
|
||
|
int get_module_size(MODULUS *j) {
|
||
|
int a, b, c, d = 0, e;
|
||
|
a = sizeof(MODULUS) + j->NumOrders;
|
||
|
b = j->NumInstruments * sizeof(MODULUS_INSTRUMENT);
|
||
|
c = j->NumSamples * sizeof(MODULUS_SAMPLE);
|
||
|
|
||
|
for (int i=0; i<j->NumSamples; i++)
|
||
|
d += j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
|
||
|
|
||
|
e = 4 + sizeof(MODULUS_PATTERN) * j->NumPatterns;
|
||
|
|
||
|
for (int i=0; i<j->NumPatterns; i++)
|
||
|
e += j->Pattern[i].NumNotes * sizeof(MODULUS_NOTE);
|
||
|
#ifdef DEBUG_IT_SIZE
|
||
|
printf("Base: %i, Instruments(%i): %i, Samples(%i): %i, Data: %i, Patterns(%i): %i\n", a, j->NumInstruments, b, j->NumSamples, c, d, j->NumPatterns, e);
|
||
|
#endif
|
||
|
|
||
|
return a+b+c+d+e;
|
||
|
}
|
||
|
|
||
|
#define MAX_IT_CHN 64
|
||
|
|
||
|
//#define DEBUG_HEADER
|
||
|
//#define DEBUG_INSTRUMENTS
|
||
|
//#define DEBUG_SAMPLES
|
||
|
//#define DEBUG_PATTERNS
|
||
|
|
||
|
static dword *sourcebuf = NULL;
|
||
|
static dword *sourcepos = NULL;
|
||
|
static byte rembits = 0;
|
||
|
|
||
|
int readblock(PACKFILE *f) {
|
||
|
long size;
|
||
|
int c = pack_igetw(f);
|
||
|
if (c == -1)
|
||
|
return 0;
|
||
|
size = c;
|
||
|
|
||
|
sourcebuf = (dword*)malloc(size+4);
|
||
|
if (!sourcebuf)
|
||
|
return 0;
|
||
|
|
||
|
c = pack_fread(sourcebuf, size, f);
|
||
|
if (c < 1) {
|
||
|
free(sourcebuf);
|
||
|
sourcebuf = NULL;
|
||
|
return 0;
|
||
|
}
|
||
|
sourcepos = sourcebuf;
|
||
|
rembits = 32;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void freeblock() {
|
||
|
if (sourcebuf)
|
||
|
free(sourcebuf);
|
||
|
sourcebuf = NULL;
|
||
|
}
|
||
|
|
||
|
dword readbits(char b) {
|
||
|
dword val;
|
||
|
if (b <= rembits) {
|
||
|
val = *sourcepos & ((1 << b) - 1);
|
||
|
*sourcepos >>= b;
|
||
|
rembits -= b;
|
||
|
}
|
||
|
else {
|
||
|
dword nbits = b - rembits;
|
||
|
val = *sourcepos;
|
||
|
sourcepos++;
|
||
|
val |= ((*sourcepos & ((1 << nbits) - 1)) << rembits);
|
||
|
*sourcepos >>= nbits;
|
||
|
rembits = 32 - nbits;
|
||
|
}
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
void decompress8(PACKFILE *f, void *data, int len, int tver) {
|
||
|
char *destbuf = (char*)data;
|
||
|
char *destpos = destbuf;
|
||
|
int blocklen, blockpos;
|
||
|
byte bitwidth;
|
||
|
word val;
|
||
|
char d1, d2;
|
||
|
|
||
|
memset(destbuf, 0, len);
|
||
|
|
||
|
while (len>0) {
|
||
|
//Read a block of compressed data:
|
||
|
if (!readblock(f))
|
||
|
return;
|
||
|
//Set up a few variables
|
||
|
blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
|
||
|
blockpos = 0;
|
||
|
bitwidth = 9;
|
||
|
d1 = d2 = 0;
|
||
|
//Start the decompression:
|
||
|
while (blockpos < blocklen) {
|
||
|
//Read a value:
|
||
|
val = readbits(bitwidth);
|
||
|
//Check for bit width change:
|
||
|
|
||
|
if (bitwidth < 7) { //Method 1:
|
||
|
if (val == (1 << (bitwidth - 1))) {
|
||
|
val = readbits(3) + 1;
|
||
|
bitwidth = (val < bitwidth) ? val : val + 1;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else if (bitwidth < 9) { //Method 2
|
||
|
byte border = (0xFF >> (9 - bitwidth)) - 4;
|
||
|
|
||
|
if (val > border && val <= (border + 8)) {
|
||
|
val -= border;
|
||
|
bitwidth = (val < bitwidth) ? val : val + 1;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else if (bitwidth == 9) { //Method 3
|
||
|
if (val & 0x100) {
|
||
|
bitwidth = (val + 1) & 0xFF;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else { //Illegal width, abort ?
|
||
|
freeblock();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//Expand the value to signed byte:
|
||
|
char v; //The sample value:
|
||
|
if (bitwidth < 8) {
|
||
|
byte shift = 8 - bitwidth;
|
||
|
v = (val << shift);
|
||
|
v >>= shift;
|
||
|
}
|
||
|
else
|
||
|
v = (char)val;
|
||
|
|
||
|
//And integrate the sample value
|
||
|
//(It always has to end with integration doesn't it ? ;-)
|
||
|
d1 += v;
|
||
|
d2 += d1;
|
||
|
|
||
|
//Store !
|
||
|
*destpos = ((tver == 0x215) ? d2 : d1);
|
||
|
destpos++;
|
||
|
blockpos++;
|
||
|
}
|
||
|
freeblock();
|
||
|
len -= blocklen;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void decompress16(PACKFILE *f, void *data, int len, int tver) {
|
||
|
//make the output buffer:
|
||
|
short *destbuf = (short*)data;
|
||
|
short *destpos = destbuf;
|
||
|
int blocklen, blockpos;
|
||
|
byte bitwidth;
|
||
|
long val;
|
||
|
short d1, d2;
|
||
|
|
||
|
memset(destbuf, 0, len);
|
||
|
|
||
|
while (len>0) {
|
||
|
//Read a block of compressed data:
|
||
|
if (!readblock(f))
|
||
|
return;
|
||
|
//Set up a few variables
|
||
|
blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
|
||
|
blockpos = 0;
|
||
|
bitwidth = 17;
|
||
|
d1 = d2 = 0;
|
||
|
//Start the decompression:
|
||
|
while (blockpos < blocklen) {
|
||
|
val = readbits(bitwidth);
|
||
|
//Check for bit width change:
|
||
|
|
||
|
if (bitwidth < 7) { //Method 1:
|
||
|
if (val == (1 << (bitwidth - 1))) {
|
||
|
val = readbits(4) + 1;
|
||
|
bitwidth = (val < bitwidth) ? val : val + 1;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else if (bitwidth < 17) { //Method 2
|
||
|
word border = (0xFFFF >> (17 - bitwidth)) - 8;
|
||
|
|
||
|
if (val > border && val <= (border + 16)) {
|
||
|
val -= border;
|
||
|
bitwidth = val < bitwidth ? val : val + 1;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else if (bitwidth == 17) { //Method 3
|
||
|
if (val & 0x10000) {
|
||
|
bitwidth = (val + 1) & 0xFF;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else { //Illegal width, abort ?
|
||
|
freeblock();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//Expand the value to signed byte:
|
||
|
short v; //The sample value:
|
||
|
if (bitwidth < 16) {
|
||
|
byte shift = 16 - bitwidth;
|
||
|
v = (val << shift);
|
||
|
v >>= shift;
|
||
|
}
|
||
|
else
|
||
|
v = (short)val;
|
||
|
|
||
|
//And integrate the sample value
|
||
|
//(It always has to end with integration doesn't it ? ;-)
|
||
|
d1 += v;
|
||
|
d2 += d1;
|
||
|
|
||
|
//Store !
|
||
|
*destpos = ((tver == 0x215) ? d2 : d1);
|
||
|
destpos++;
|
||
|
blockpos++;
|
||
|
}
|
||
|
freeblock();
|
||
|
len -= blocklen;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
MODULUS *load_it(char *file) {
|
||
|
PACKFILE *f;
|
||
|
MODULUS *j = create_it();
|
||
|
int tver, tver2, flag, msglen, msgoffs;
|
||
|
int *insoffs = NULL, *samoffs = NULL, *patoffs = NULL;
|
||
|
|
||
|
if (!j)
|
||
|
return NULL;
|
||
|
|
||
|
if (!detect_it(file))
|
||
|
return NULL;
|
||
|
|
||
|
f = pack_fopen(file, "rb");
|
||
|
|
||
|
if (!f) {
|
||
|
#ifdef DEBUG_HEADER
|
||
|
printf("Error Opening!\n");
|
||
|
#endif
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pack_fseek(f, 30);
|
||
|
pack_igetw(f); //I have no idea...
|
||
|
|
||
|
j->NumOrders = pack_igetw(f);
|
||
|
j->NumInstruments = pack_igetw(f);
|
||
|
j->NumSamples = pack_igetw(f);
|
||
|
j->NumPatterns = pack_igetw(f);
|
||
|
|
||
|
#ifdef DEBUG_HEADER
|
||
|
printf("Loading IT: %i Orders %i Instruments, %i Samples, %i Patterns\n", j->NumOrders, j->NumInstruments, j->NumSamples, j->NumPatterns);
|
||
|
#endif
|
||
|
|
||
|
tver = pack_igetw(f);
|
||
|
j->Version = tver2 = pack_igetw(f);
|
||
|
|
||
|
#ifdef DEBUG_HEADER
|
||
|
printf("Tracker ver: %X, %X\n", tver, tver2);
|
||
|
#endif
|
||
|
|
||
|
j->Flags = pack_igetw(f);
|
||
|
flag = pack_igetw(f);
|
||
|
|
||
|
j->GlobalVolume = pack_getc(f);
|
||
|
j->MixVolume = pack_getc(f);
|
||
|
j->Speed = pack_getc(f);
|
||
|
j->Tempo = pack_getc(f);
|
||
|
j->PanningSeperation = pack_getc(f);
|
||
|
|
||
|
#ifdef DEBUG_HEADER
|
||
|
printf("Global Volume: %i, Mixing Volume: %i, Speed: %i, Tempo: %i, PanSep: %i\n", j->GlobalVolume, j->MixVolume, j->Speed, j->Tempo, j->PanningSeperation);
|
||
|
#endif
|
||
|
|
||
|
pack_getc(f); //Damn....I need more info on this.
|
||
|
|
||
|
msglen = pack_igetw(f);
|
||
|
msgoffs = pack_igetl(f);
|
||
|
|
||
|
pack_fseek(f, 4);
|
||
|
|
||
|
#ifdef DEBUG_HEADER
|
||
|
printf("Channel Pan:");
|
||
|
#endif
|
||
|
|
||
|
for (int i=0; i<MAX_IT_CHN; i++) {
|
||
|
j->Channel[i].Pan = pack_getc(f);
|
||
|
#ifdef DEBUG_HEADER
|
||
|
printf(" %i", j->Channel[i].Pan);
|
||
|
#endif
|
||
|
}
|
||
|
#ifdef DEBUG_HEADER
|
||
|
printf("\nChannel Vol:");
|
||
|
#endif
|
||
|
for (int i=0; i<MAX_IT_CHN; i++) {
|
||
|
j->Channel[i].Volume = pack_getc(f);
|
||
|
#ifdef DEBUG_HEADER
|
||
|
printf(" %i", j->Channel[i].Volume);
|
||
|
#endif
|
||
|
}
|
||
|
#ifdef DEBUG_HEADER
|
||
|
printf("\n");
|
||
|
#endif
|
||
|
|
||
|
j->Order = (unsigned char *)malloc(j->NumOrders);
|
||
|
pack_fread(j->Order, j->NumOrders, f);
|
||
|
|
||
|
if (j->NumInstruments)
|
||
|
insoffs = (int*)malloc(4 * j->NumInstruments);
|
||
|
if (j->NumSamples)
|
||
|
samoffs = (int*)malloc(4 * j->NumSamples);
|
||
|
if (j->NumPatterns)
|
||
|
patoffs = (int*)malloc(4 * j->NumPatterns);
|
||
|
|
||
|
pack_fread(insoffs, 4 * j->NumInstruments, f);
|
||
|
pack_fread(samoffs, 4 * j->NumSamples, f);
|
||
|
pack_fread(patoffs, 4 * j->NumPatterns, f);
|
||
|
|
||
|
if (flag&1) { //Song message attached
|
||
|
//Ignore.
|
||
|
}
|
||
|
if (flag & 4) { //skip something:
|
||
|
short u;
|
||
|
char dummy[8];
|
||
|
u = pack_igetw(f);
|
||
|
for (int i=0; i<u; u++)
|
||
|
pack_fread(dummy, 8, f);
|
||
|
}
|
||
|
if (flag & 8) { //MIDI commands ???
|
||
|
char dummy[33];
|
||
|
for (int i=0; i<9+16+128; i++)
|
||
|
pack_fread(dummy, 32, f);
|
||
|
|
||
|
}
|
||
|
|
||
|
if (j->NumInstruments)
|
||
|
j->Instrument = (MODULUS_INSTRUMENT*)malloc(sizeof(MODULUS_INSTRUMENT) * j->NumInstruments);
|
||
|
#ifdef DEBUG_INSTRUMENTS
|
||
|
if (!j->Instrument)
|
||
|
printf("No Mem for Instruments!\n");
|
||
|
#endif
|
||
|
|
||
|
|
||
|
for (int i=0; i<j->NumInstruments; i++) {
|
||
|
pack_fclose(f);
|
||
|
f = pack_fopen(file, "rb");
|
||
|
#ifdef DEBUG_INSTRUMENTS
|
||
|
if (!f)
|
||
|
printf("Error Opening!\n");
|
||
|
#endif
|
||
|
pack_fseek(f, insoffs[i] + 17);
|
||
|
|
||
|
j->Instrument[i].NewNoteAction = pack_getc(f);
|
||
|
j->Instrument[i].DuplicateCheckType = pack_getc(f);
|
||
|
j->Instrument[i].DuplicateCheckAction = pack_getc(f);
|
||
|
j->Instrument[i].FadeOut = pack_igetw(f);
|
||
|
j->Instrument[i].PitchPanSeperation = pack_getc(f);
|
||
|
j->Instrument[i].PitchPanCenter = pack_getc(f);
|
||
|
j->Instrument[i].GlobalVolume = pack_getc(f);
|
||
|
j->Instrument[i].DefaultPan = pack_getc(f);
|
||
|
#ifdef DEBUG_INSTRUMENTS
|
||
|
printf("I%02i @ 0x%X, NNA %i, DCT %i, DCA %i, FO %i, PPS %i, PPC %i, GVol %i, DPan %i\n", i, insoffs[i], j->Instrument[i].NewNoteAction, j->Instrument[i].DuplicateCheckType, j->Instrument[i].DuplicateCheckAction, j->Instrument[i].FadeOut, j->Instrument[i].PitchPanSeperation, j->Instrument[i].PitchPanCenter, j->Instrument[i].GlobalVolume, j->Instrument[i].DefaultPan);
|
||
|
#endif
|
||
|
|
||
|
pack_fseek(f, 38);
|
||
|
|
||
|
for (int k=0; k<120; k++) {
|
||
|
j->Instrument[i].NoteNote[k] = pack_getc(f);
|
||
|
j->Instrument[i].NoteSample[k] = pack_getc(f) - 1;
|
||
|
}
|
||
|
|
||
|
j->Instrument[i].VolumeEnvelope.Flag = pack_getc(f);
|
||
|
j->Instrument[i].VolumeEnvelope.NumNodes = pack_getc(f);
|
||
|
j->Instrument[i].VolumeEnvelope.LoopBegin = pack_getc(f);
|
||
|
j->Instrument[i].VolumeEnvelope.LoopEnd = pack_getc(f);
|
||
|
j->Instrument[i].VolumeEnvelope.SustainLoopBegin = pack_getc(f);
|
||
|
j->Instrument[i].VolumeEnvelope.SustainLoopEnd = pack_getc(f);
|
||
|
for (int k=0; k<j->Instrument[i].VolumeEnvelope.NumNodes; k++) {
|
||
|
j->Instrument[i].VolumeEnvelope.NodeY[k] = pack_getc(f);
|
||
|
j->Instrument[i].VolumeEnvelope.NodeTick[k] = pack_igetw(f);
|
||
|
}
|
||
|
pack_fseek(f, 75 - j->Instrument[i].VolumeEnvelope.NumNodes * 3);
|
||
|
|
||
|
j->Instrument[i].PanningEnvelope.Flag = pack_getc(f);
|
||
|
j->Instrument[i].PanningEnvelope.NumNodes = pack_getc(f);
|
||
|
j->Instrument[i].PanningEnvelope.LoopBegin = pack_getc(f);
|
||
|
j->Instrument[i].PanningEnvelope.LoopEnd = pack_getc(f);
|
||
|
j->Instrument[i].PanningEnvelope.SustainLoopBegin = pack_getc(f);
|
||
|
j->Instrument[i].PanningEnvelope.SustainLoopEnd = pack_getc(f);
|
||
|
for (int k=0; k<j->Instrument[i].PanningEnvelope.NumNodes; k++) {
|
||
|
j->Instrument[i].PanningEnvelope.NodeY[k] = pack_getc(f);
|
||
|
j->Instrument[i].PanningEnvelope.NodeTick[k] = pack_igetw(f);
|
||
|
}
|
||
|
pack_fseek(f, 75 - j->Instrument[i].PanningEnvelope.NumNodes * 3);
|
||
|
|
||
|
j->Instrument[i].PitchEnvelope.Flag = pack_getc(f);
|
||
|
j->Instrument[i].PitchEnvelope.NumNodes = pack_getc(f);
|
||
|
j->Instrument[i].PitchEnvelope.LoopBegin = pack_getc(f);
|
||
|
j->Instrument[i].PitchEnvelope.LoopEnd = pack_getc(f);
|
||
|
j->Instrument[i].PitchEnvelope.SustainLoopBegin = pack_getc(f);
|
||
|
j->Instrument[i].PitchEnvelope.SustainLoopEnd = pack_getc(f);
|
||
|
for (int k=0; k<j->Instrument[i].PitchEnvelope.NumNodes; k++) {
|
||
|
j->Instrument[i].PitchEnvelope.NodeY[k] = pack_getc(f);
|
||
|
j->Instrument[i].PitchEnvelope.NodeTick[k] = pack_igetw(f);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (j->NumSamples)
|
||
|
j->Sample = (MODULUS_SAMPLE*)malloc(sizeof(MODULUS_SAMPLE) * j->NumSamples);
|
||
|
|
||
|
#ifdef DEBUG_SAMPLES
|
||
|
if (!j->Sample)
|
||
|
printf("No Mem for Samples!\n");
|
||
|
#endif
|
||
|
|
||
|
for (int i=0; i<j->NumSamples; i++) {
|
||
|
int sam_samptr, convert;
|
||
|
|
||
|
pack_fclose(f);
|
||
|
f = pack_fopen(file, "rb");
|
||
|
#ifdef DEBUG_SAMPLES
|
||
|
if (!f)
|
||
|
printf("Error opening!\n");
|
||
|
#endif
|
||
|
|
||
|
pack_fseek(f, samoffs[i] + 17);
|
||
|
|
||
|
j->Sample[i].GlobalVolume = pack_getc(f);
|
||
|
j->Sample[i].Flag = pack_getc(f);
|
||
|
j->Sample[i].Volume = pack_getc(f);
|
||
|
|
||
|
#ifdef DEBUG_SAMPLES
|
||
|
printf("S%02i @ 0x%X, Vol: %i/%i, Flag: %i", i, samoffs[i], j->Sample[i].GlobalVolume, j->Sample[i].Volume, j->Sample[i].Flag);
|
||
|
#endif
|
||
|
|
||
|
pack_fseek(f, 26);
|
||
|
|
||
|
convert = pack_getc(f);
|
||
|
pack_getc(f); //Panning ?
|
||
|
|
||
|
j->Sample[i].SampleLength = pack_igetl(f);
|
||
|
j->Sample[i].LoopBegin = pack_igetl(f);
|
||
|
j->Sample[i].LoopEnd = pack_igetl(f);
|
||
|
j->Sample[i].C5Speed = pack_igetl(f);
|
||
|
j->Sample[i].SustainLoopBegin = pack_igetl(f);
|
||
|
j->Sample[i].SustainLoopEnd = pack_igetl(f);
|
||
|
|
||
|
#ifdef DEBUG_SAMPLES
|
||
|
printf(", SLen: %i, LpB: %i, LpE: %i, C5S: %i\n", j->Sample[i].SampleLength, j->Sample[i].LoopBegin, j->Sample[i].LoopEnd, j->Sample[i].C5Speed);
|
||
|
#endif
|
||
|
|
||
|
sam_samptr = pack_igetl(f);
|
||
|
|
||
|
j->Sample[i].VibratoSpeed = pack_getc(f);
|
||
|
j->Sample[i].VibratoDepth = pack_getc(f);
|
||
|
j->Sample[i].VibratoRate = pack_getc(f);
|
||
|
j->Sample[i].VibratoWaveForm = pack_getc(f);
|
||
|
|
||
|
#ifdef DEBUG_SAMPLES
|
||
|
printf("SusLpB: %i, SusLpE: %i, VibSp: %i, VibDep: %i, VibWav: %i, VibRat: %i\n", j->Sample[i].SustainLoopBegin, j->Sample[i].SustainLoopEnd, j->Sample[i].VibratoSpeed, j->Sample[i].VibratoDepth, j->Sample[i].VibratoWaveForm, j->Sample[i].VibratoRate);
|
||
|
#endif
|
||
|
|
||
|
if (j->Sample[i].Flag & 1 == 0)
|
||
|
continue;
|
||
|
|
||
|
pack_fclose(f);
|
||
|
f = pack_fopen(file, "rb");
|
||
|
pack_fseek(f, sam_samptr);
|
||
|
|
||
|
int len = j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
|
||
|
|
||
|
#ifdef DEBUG_SAMPLES
|
||
|
printf("Len: %i, Size: %i KB\n", j->Sample[i].SampleLength, len/1024);
|
||
|
#endif
|
||
|
|
||
|
SAMPLE *sam = create_sample(j->Sample[i].Flag & 2 ? 16 : 8, j->Sample[i].Flag & 4 ? TRUE : FALSE, j->Sample[i].C5Speed, j->Sample[i].SampleLength);
|
||
|
|
||
|
if (j->Sample[i].Flag & 8) { // If the sample is packed, then we must unpack it
|
||
|
if (j->Sample[i].Flag & 2)
|
||
|
decompress16(f, sam->data, j->Sample[i].SampleLength, tver2);
|
||
|
else
|
||
|
decompress8(f, sam->data, j->Sample[i].SampleLength, tver2);
|
||
|
} else {
|
||
|
pack_fread(sam->data, len, f);
|
||
|
}
|
||
|
|
||
|
if (j->Sample[i].Flag & SAMPLE_USELOOP) {
|
||
|
sam->loop_start = j->Sample[i].LoopBegin;
|
||
|
sam->loop_end = j->Sample[i].LoopEnd;
|
||
|
}
|
||
|
|
||
|
j->Sample[i].Sample = sam;
|
||
|
|
||
|
void *dat = sam->data;
|
||
|
|
||
|
if (convert & 2) { //Change the byte order for 16-bit samples:
|
||
|
if (sam->bits == 16) {
|
||
|
for (int k=0; k<len; k+=2) {
|
||
|
int l = ((char*)dat)[k];
|
||
|
((char*)dat)[k] = ((char*)dat)[k+1];
|
||
|
((char*)dat)[k+1] = l;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
for (int k=0; k<len; k+=2) {
|
||
|
int l = ((char*)dat)[k];
|
||
|
((char*)dat)[k] = ((char*)dat)[k+1];
|
||
|
((char*)dat)[k+1] = l;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (convert & 1) { //Convert to unsigned
|
||
|
if (sam->bits == 8) {
|
||
|
for (int k=0; k<len; k++) {
|
||
|
((char*)dat)[k] ^= 0x80;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
for (int k=0; k<(len>>1); k++) {
|
||
|
((short*)dat)[k] ^= 0x8000;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (j->NumPatterns)
|
||
|
j->Pattern = (MODULUS_PATTERN*)malloc(sizeof(MODULUS_PATTERN) * j->NumPatterns);
|
||
|
unsigned char *buf = (unsigned char*)alloca(65536);
|
||
|
unsigned char *cmask = (unsigned char*)alloca(64),
|
||
|
*cnote = (unsigned char*)alloca(64),
|
||
|
*cinstrument = (unsigned char*)alloca(64),
|
||
|
*cvol = (unsigned char*)alloca(64),
|
||
|
*ccom = (unsigned char*)alloca(64),
|
||
|
*ccomval = (unsigned char*)alloca(64);
|
||
|
|
||
|
for (int i=0; i<j->NumPatterns; i++) {
|
||
|
int numnotes = 0, len, pos = 0, mask = 0, chn = 0;
|
||
|
|
||
|
memset(cmask, 0, 64);
|
||
|
memset(cnote, 0, 64);
|
||
|
memset(cinstrument, 0, 64);
|
||
|
memset(cvol, 0, 64);
|
||
|
memset(ccom, 0, 64);
|
||
|
memset(ccomval, 0, 64);
|
||
|
|
||
|
pack_fclose(f);
|
||
|
f = pack_fopen(file, "rb");
|
||
|
pack_fseek(f, patoffs[i]);
|
||
|
|
||
|
len = pack_igetw(f);
|
||
|
j->Pattern[i].NumRows = pack_igetw(f);
|
||
|
|
||
|
pack_fseek(f, 4);
|
||
|
pack_fread(buf, len, f);
|
||
|
|
||
|
while (pos < len) {
|
||
|
int b = buf[pos];
|
||
|
pos++;
|
||
|
if (!b) { //If end of row:
|
||
|
numnotes++;
|
||
|
continue;
|
||
|
}
|
||
|
chn = (b - 1) & 63;
|
||
|
|
||
|
if (b & 128) {
|
||
|
mask = buf[pos];
|
||
|
pos++;
|
||
|
cmask[chn] = mask;
|
||
|
}
|
||
|
else
|
||
|
mask = cmask[chn];
|
||
|
|
||
|
if (mask)
|
||
|
numnotes++;
|
||
|
if (mask & 1)
|
||
|
pos++;
|
||
|
if (mask & 2)
|
||
|
pos++;
|
||
|
if (mask & 4)
|
||
|
pos++;
|
||
|
if (mask & 8)
|
||
|
pos+=2; //Guessing here
|
||
|
}
|
||
|
j->Pattern[i].NumNotes = numnotes;
|
||
|
j->Pattern[i].Note = (MODULUS_NOTE*)malloc(sizeof(MODULUS_NOTE) * numnotes);
|
||
|
memset(j->Pattern[i].Note, 0, sizeof(MODULUS_NOTE) * numnotes);
|
||
|
|
||
|
pos = 0;
|
||
|
memset(cmask, 0, 64);
|
||
|
mask = 0;
|
||
|
numnotes = 0;
|
||
|
while (pos < len) {
|
||
|
int b = buf[pos];
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("NumNote: %i ", numnotes);
|
||
|
#endif
|
||
|
|
||
|
pos++;
|
||
|
if (!b) { //If end of row:
|
||
|
j->Pattern[i].Note[numnotes].Channel = -1;
|
||
|
numnotes++;
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("Channel: -1\n");
|
||
|
#endif
|
||
|
continue;
|
||
|
}
|
||
|
chn = (b - 1) & 63;
|
||
|
|
||
|
if (b & 128) {
|
||
|
mask = buf[pos];
|
||
|
pos++;
|
||
|
cmask[chn] = mask;
|
||
|
}
|
||
|
else
|
||
|
mask = cmask[chn];
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("Channel: %i Mask: %i ", chn, mask);
|
||
|
#endif
|
||
|
|
||
|
if (mask)
|
||
|
j->Pattern[i].Note[numnotes].Channel = chn;
|
||
|
|
||
|
if (mask & 1) {
|
||
|
j->Pattern[i].Note[numnotes].Note = buf[pos];
|
||
|
j->Pattern[i].Note[numnotes].Mask |= 1;
|
||
|
cnote[chn] = buf[pos];
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("Note: %i ", buf[pos]);
|
||
|
#endif
|
||
|
pos++;
|
||
|
}
|
||
|
if (mask & 2) {
|
||
|
j->Pattern[i].Note[numnotes].Instrument = buf[pos];
|
||
|
j->Pattern[i].Note[numnotes].Mask |= 2;
|
||
|
cinstrument[chn] = buf[pos];
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("Inst: %i ", buf[pos]);
|
||
|
#endif
|
||
|
pos++;
|
||
|
}
|
||
|
if (mask & 4) {
|
||
|
if (buf[pos] <= 64 || (buf[pos] >= 128 && buf[pos] <= 192))
|
||
|
if (buf[pos] <= 64) {
|
||
|
j->Pattern[i].Note[numnotes].Volume = buf[pos];
|
||
|
j->Pattern[i].Note[numnotes].Mask |= 4;
|
||
|
}
|
||
|
else {
|
||
|
j->Pattern[i].Note[numnotes].Panning = buf[pos] - 128;
|
||
|
j->Pattern[i].Note[numnotes].Mask |= 8;
|
||
|
}
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("Vol: %i ", buf[pos]);
|
||
|
#endif
|
||
|
cvol[chn] = buf[pos];
|
||
|
pos++;
|
||
|
}
|
||
|
if (mask & 8) {
|
||
|
j->Pattern[i].Note[numnotes].Command = buf[pos];
|
||
|
j->Pattern[i].Note[numnotes].CommandValue = buf[pos+1];
|
||
|
j->Pattern[i].Note[numnotes].Mask |= 16;
|
||
|
ccom[chn] = buf[pos];
|
||
|
ccomval[chn] = buf[pos+1];
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("Com: %i CommArg: %i ", buf[pos], buf[pos+1]);
|
||
|
#endif
|
||
|
pos+=2;
|
||
|
}
|
||
|
if (mask & 16) {
|
||
|
j->Pattern[i].Note[numnotes].Note = cnote[chn];
|
||
|
j->Pattern[i].Note[numnotes].Mask |= 1;
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("LNote: %i ", cnote[chn]);
|
||
|
#endif
|
||
|
}
|
||
|
if (mask & 32) {
|
||
|
j->Pattern[i].Note[numnotes].Instrument = cinstrument[chn];
|
||
|
j->Pattern[i].Note[numnotes].Mask |= 2;
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("LInst: %i ", cinstrument[chn]);
|
||
|
#endif
|
||
|
}
|
||
|
if (mask & 64) {
|
||
|
if (cvol[chn] <= 64 || (cvol[chn] >= 128 && cvol[chn] <= 192))
|
||
|
if (cvol[chn] <= 64) {
|
||
|
j->Pattern[i].Note[numnotes].Volume = cvol[chn];
|
||
|
j->Pattern[i].Note[numnotes].Mask |= 4;
|
||
|
}
|
||
|
else {
|
||
|
j->Pattern[i].Note[numnotes].Panning = cvol[chn] - 128;
|
||
|
j->Pattern[i].Note[numnotes].Mask |= 8;
|
||
|
}
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("LVol: %i ", cvol[chn]);
|
||
|
#endif
|
||
|
}
|
||
|
if (mask & 128) {
|
||
|
j->Pattern[i].Note[numnotes].Command = ccom[chn];
|
||
|
j->Pattern[i].Note[numnotes].CommandValue = ccomval[chn];
|
||
|
j->Pattern[i].Note[numnotes].Mask |= 16;
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("LCom: %i LComArg: %i ", ccom[chn], ccomval[chn]);
|
||
|
#endif
|
||
|
}
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
printf("\n");
|
||
|
#endif
|
||
|
if (mask)
|
||
|
numnotes++;
|
||
|
#ifdef DEBUG_PATTERNS
|
||
|
rest(1000);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
if (insoffs)
|
||
|
free(insoffs);
|
||
|
if (samoffs)
|
||
|
free(samoffs);
|
||
|
if (patoffs)
|
||
|
free(patoffs);
|
||
|
|
||
|
return j;
|
||
|
}
|