qzdoom/dumb/src/tools/it/load_it.cpp
Randy Heit 01f59fa85f - Added an alternate module replay engine that uses foo_dumb's replayer, a
heavily customized version of DUMB (Dynamic Universal Music Bibliotheque).
  It has been slightly modified by me:
  * Added support for Ogg Vorbis-compressed samples in XM files ala FMOD.
  * Removed excessive mallocs from the replay core.
  * Rerolled the loops in resample.c. Unrolling them made the object file
    ~250k large while providing little benefit. Even at ~100k, I think it's
    still larger than it ought to be, but I'll live with it for now.
  Other than that, it's essentially the same thing you'd hear in foobar2000,
  minus some subsong detection features. Release builds of the library look
  like they might even be slightly faster than FMOD, which is a plus.
- Fixed: Timidity::font_add() did not release the file reader it created.
- Fixed: The SF2 loader did not free the sample headers in its destructor.


SVN r995 (trunk)
2008-05-29 23:33:07 +00:00

824 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;
}