cog/Frameworks/Syntrax-c/Syntrax-c/file.c

401 lines
13 KiB
C

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "file.h"
size_t filesize;
Song* File_loadSong(const char *path)
{
Song *synSong;
FILE *f;
uint8_t *buffer;
size_t size;
if (!(f = fopen(path, "rb"))) return NULL;
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
if (!(buffer = (uint8_t *) malloc(size))) {
fclose(f);
return NULL;
}
if (fread(buffer, 1, size, f) != size) {
free(buffer);
fclose(f);
return NULL;
}
fclose(f);
synSong = File_loadSongMem(buffer, size);
free(buffer);
return synSong;
}
uint16_t get_le16(const void *p)
{
return (((const uint8_t*)p)[0]) +
(((const uint8_t*)p)[1]) * 0x100;
}
uint32_t get_le32(const void *p)
{
return (((const uint8_t*)p)[0]) +
(((const uint8_t*)p)[1]) * 0x100 +
(((const uint8_t*)p)[2]) * 0x10000 +
(((const uint8_t*)p)[3]) * 0x1000000;
}
static long File_readHeader(SongHeader *h, const uint8_t *buffer, size_t size)
{
if (size < 52) return -1;
h->version = get_le16(buffer);
h->UNK00 = get_le16(buffer + 2);
h->patNum = get_le32(buffer + 4);
h->subsongNum = get_le32(buffer + 8);
h->instrNum = get_le32(buffer + 12);
h->UNK01 = get_le32(buffer + 16);
h->UNK02 = get_le16(buffer + 20);
h->UNK03 = get_le16(buffer + 22);
h->UNK04 = get_le16(buffer + 24);
h->UNK05 = get_le16(buffer + 26);
h->UNK06 = get_le16(buffer + 28);
h->UNK07 = get_le16(buffer + 30);
h->UNK08 = get_le16(buffer + 32);
h->UNK09 = get_le16(buffer + 34);
h->UNK0A = get_le16(buffer + 36);
h->UNK0B = get_le16(buffer + 38);
h->UNK0C = get_le16(buffer + 40);
h->UNK0D = get_le16(buffer + 42);
h->UNK0E = get_le16(buffer + 44);
h->UNK0F = get_le16(buffer + 46);
h->UNK10 = get_le16(buffer + 48);
h->UNK11 = get_le16(buffer + 50);
return 52;
}
static long File_readSubSong(Subsong *subSong, const uint8_t *buffer, size_t size)
{
int i, j;
if (size < 16564) return -1;
for (i = 0; i < 16; i++)
subSong->UNK00[i] = get_le32(buffer + i * 4);
for (i = 0; i < SE_MAXCHANS; i++)
subSong->mutedChans[i] = buffer[64 + i];
subSong->tempo = get_le32(buffer + 80);
subSong->groove = get_le32(buffer + 84);
subSong->startPosCoarse = get_le32(buffer + 88);
subSong->startPosFine = get_le32(buffer + 92);
subSong->endPosCoarse = get_le32(buffer + 96);
subSong->endPosFine = get_le32(buffer + 100);
subSong->loopPosCoarse = get_le32(buffer + 104);
subSong->loopPosFine = get_le32(buffer + 108);
subSong->isLooping = get_le16(buffer + 112);
memcpy(subSong->m_Name, buffer + 114, 32);
subSong->m_Name[32] = '\0';
subSong->channelNumber = get_le16(buffer + 146);
subSong->delayTime = get_le16(buffer + 148);
for (i = 0; i < SE_MAXCHANS; i++)
subSong->chanDelayAmt[i] = buffer[150 + i];
subSong->amplification = get_le16(buffer + 166);
subSong->UNK01 = get_le16(buffer + 168);
subSong->UNK02 = get_le16(buffer + 170);
subSong->UNK03 = get_le16(buffer + 172);
subSong->UNK04 = get_le16(buffer + 174);
subSong->UNK05 = get_le16(buffer + 176);
subSong->UNK06 = get_le16(buffer + 178);
for (i = 0; i < SE_MAXCHANS; i++) {
for (j = 0; j < 0x100; j++) {
subSong->orders[i][j].patIndex = get_le16(buffer + 180 + i * 1024 + j * 4);
subSong->orders[i][j].patLen = get_le16(buffer + 180 + i * 1024 + j * 4 + 2);
}
}
return 16564;
}
long File_readRow(Row *r, const uint8_t *buffer, size_t size)
{
if (size < 5) return -1;
r->note = buffer[0];
r->dest = buffer[1];
r->instr = buffer[2];
r->spd = buffer[3];
r->command = buffer[4];
return 5;
}
static long File_readInstrumentEffect(InstrumentEffect *effect, const uint8_t *buffer, size_t size)
{
if (size < 40) return -1;
effect->destWave = get_le32(buffer);
effect->srcWave1 = get_le32(buffer + 4);
effect->srcWave2 = get_le32(buffer + 8);
effect->oscWave = get_le32(buffer + 12);
effect->variable1 = get_le32(buffer + 16);
effect->variable2 = get_le32(buffer + 20);
effect->fxSpeed = get_le32(buffer + 24);
effect->oscSpeed = get_le32(buffer + 28);
effect->effectType = get_le32(buffer + 32);
effect->oscSelect = buffer[36];
effect->resetEffect = buffer[37];
effect->UNK00 = get_le16(buffer + 38);
return 40;
}
static long File_readInstrument(Instrument *instr, const uint8_t *buffer, size_t size)
{
int i, j;
long sizeRead;
if (size < 8712) return -1;
instr->version = get_le16(buffer);
memcpy(instr->name, buffer + 2, 32);
instr->name[32] = '\0';
instr->waveform = get_le16(buffer + 34);
instr->wavelength = get_le16(buffer + 36);
instr->masterVolume = get_le16(buffer + 38);
instr->amWave = get_le16(buffer + 40);
instr->amSpeed = get_le16(buffer + 42);
instr->amLoopPoint = get_le16(buffer + 44);
instr->finetune = get_le16(buffer + 46);
instr->fmWave = get_le16(buffer + 48);
instr->fmSpeed = get_le16(buffer + 50);
instr->fmLoopPoint = get_le16(buffer + 52);
instr->fmDelay = get_le16(buffer + 54);
instr->arpIndex = get_le16(buffer + 56);
for (i = 0; i < SE_MAXCHANS; i++)
instr->m_ResetWave[i] = buffer[58 + i];
instr->panWave = get_le16(buffer + 74);
instr->panSpeed = get_le16(buffer + 76);
instr->panLoopPoint = get_le16(buffer + 78);
instr->UNK00 = get_le16(buffer + 80);
instr->UNK01 = get_le16(buffer + 82);
instr->UNK02 = get_le16(buffer + 84);
instr->UNK03 = get_le16(buffer + 86);
instr->UNK04 = get_le16(buffer + 88);
instr->UNK05 = get_le16(buffer + 90);
buffer += 92; size -= 92;
for (i = 0; i < 4; i++) {
sizeRead = File_readInstrumentEffect(&instr->effects[i], buffer, size);
if (sizeRead < 0) return -1;
buffer += sizeRead; size -= sizeRead;
}
memcpy(instr->smpFullImportPath, buffer, 192);
instr->smpFullImportPath[192] = '\0';
buffer += 192; size -= 192;
instr->UNK06 = get_le32(buffer);
instr->UNK07 = get_le32(buffer + 4);
instr->UNK08 = get_le32(buffer + 8);
instr->UNK09 = get_le32(buffer + 12);
instr->UNK0A = get_le32(buffer + 16);
instr->UNK0B = get_le32(buffer + 20);
instr->UNK0C = get_le32(buffer + 24);
instr->UNK0D = get_le32(buffer + 28);
instr->UNK0E = get_le32(buffer + 32);
instr->UNK0F = get_le32(buffer + 36);
instr->UNK10 = get_le32(buffer + 40);
instr->UNK11 = get_le32(buffer + 44);
instr->UNK12 = get_le16(buffer + 48);
buffer += 50; size -= 50;
instr->shareSmpDataFromInstr = get_le16(buffer);
instr->hasLoop = get_le16(buffer + 2);
instr->hasBidiLoop = get_le16(buffer + 4);
buffer += 6; size -= 6;
instr->smpStartPoint = get_le32(buffer);
instr->smpLoopPoint = get_le32(buffer + 4);
instr->smpEndPoint = get_le32(buffer + 8);
instr->hasSample = get_le32(buffer + 12);
instr->smpLength = get_le32(buffer + 16);
buffer += 20; size -= 20;
for (i = 0; i < SE_MAXCHANS; i++) {
for (j = 0; j < 0x100; j++) {
instr->synthBuffers[i][j] = get_le16(buffer + i * 512 + j * 2);
}
}
return 8712;
}
Song* File_loadSongMem(const uint8_t *buffer, size_t size)
{
int i, j/*, k*/;
int songVer;
/*Subsong *subs;
Order *orderCol;
Order *order;
Row *row;*/
Instrument *instr;
Song *synSong;
long sizeRead;
synSong = (Song *) calloc(1, sizeof(Song));
if (!synSong) return NULL;
/*
//unused vars
int8_t _local5[] = [0, 0, 0, 0, 0, 0];
bool _local2 = false;
int _local7 = 0;
bool _local8 = true;
*/
sizeRead = File_readHeader(&synSong->h, buffer, size);
if (sizeRead < 0) goto FAIL;
buffer += sizeRead; size -= sizeRead;
songVer = synSong->h.version;
if ((songVer >= 3456) && (songVer <= 3457)){
if (synSong->h.subsongNum > 0){
synSong->subsongs = (Subsong *) malloc(synSong->h.subsongNum *sizeof(Subsong));
if (!synSong->subsongs) goto FAIL;
for (i = 0; i < synSong->h.subsongNum; i++) {
sizeRead = File_readSubSong(synSong->subsongs + i, buffer, size);
if (sizeRead < 0) goto FAIL;
buffer += sizeRead; size -= sizeRead;
}
synSong->rows = (Row *) malloc(synSong->h.patNum * 64 *sizeof(Row));
if (!synSong->rows) goto FAIL;
for (i = 0, j = synSong->h.patNum * 64; i < j; i++) {
sizeRead = File_readRow(synSong->rows + i, buffer, size);
if (sizeRead < 0) goto FAIL;
buffer += sizeRead; size -= sizeRead;
}
synSong->patNameSizes = (uint32_t *) malloc(synSong->h.patNum * sizeof(uint32_t));
if (!synSong->patNameSizes) goto FAIL;
synSong->patternNames = calloc(sizeof(char *), synSong->h.patNum);
if (!synSong->patternNames) goto FAIL;
for (i = 0; i < synSong->h.patNum; i++) {
if (size < 4) goto FAIL;
j = synSong->patNameSizes[i] = get_le32(buffer);
buffer += 4; size -= 4;
if (size < j) goto FAIL;
synSong->patternNames[i] = malloc(j + sizeof(char));
if (!synSong->patternNames[i]) goto FAIL;
memcpy(synSong->patternNames[i], buffer, j);
synSong->patternNames[i][j] = '\0';
buffer += j; size -= j;
}
synSong->instruments = malloc(synSong->h.instrNum * sizeof(Instrument));
if (!synSong->instruments) goto FAIL;
synSong->samples = calloc(sizeof(int16_t *), synSong->h.instrNum);
if (!synSong->samples) goto FAIL;
for (i = 0; i < synSong->h.instrNum; i++) {
instr = &synSong->instruments[i];
sizeRead = File_readInstrument(instr, buffer, size);
if (sizeRead < 0) goto FAIL;
buffer += sizeRead; size -= sizeRead;
if (songVer == 3456){
instr->shareSmpDataFromInstr = 0;
instr->hasLoop = 0;
instr->hasBidiLoop = 0;
instr->smpStartPoint = 0;
instr->smpLoopPoint = 0;
instr->smpEndPoint = 0;
if (instr->hasSample){
instr->smpStartPoint = 0;
instr->smpEndPoint = (instr->smpLength / 2);
instr->smpLoopPoint = 0;
}
}
if (instr->hasSample){
//instr->smpLength is in bytes, I think
if (size < instr->smpLength) goto FAIL;
synSong->samples[i] = malloc(instr->smpLength);
if (!synSong->samples[i]) goto FAIL;
memcpy(synSong->samples[i], buffer, instr->smpLength);
buffer += instr->smpLength; size -= instr->smpLength;
} else {
synSong->samples[i] = NULL;
}
}
memcpy(synSong->arpTable, buffer, 0x100);
buffer += 0x100; size -= 0x100;
} else goto FAIL;
} else goto FAIL;
return synSong;
FAIL:
File_freeSong(synSong);
return NULL;
}
void File_freeSong(Song *synSong)
{
int i;
if (synSong) {
if (synSong->subsongs) free(synSong->subsongs);
if (synSong->rows) free(synSong->rows);
if (synSong->patNameSizes) free(synSong->patNameSizes);
if (synSong->patternNames) {
for (i = 0; i < synSong->h.patNum; i++) {
if (synSong->patternNames[i]) free(synSong->patternNames[i]);
}
free(synSong->patternNames);
}
if (synSong->instruments) free(synSong->instruments);
if (synSong->samples) {
for (i = 0; i < synSong->h.instrNum; i++) {
if (synSong->samples[i]) free(synSong->samples[i]);
}
free(synSong->samples);
}
free(synSong);
}
}