Cog/Frameworks/Syntrax-c/Syntrax-c/jxs.c

359 lines
12 KiB
C

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jaytrax.h"
#include "jxs.h"
#include "ioutil.h"
struct memdata
{
const uint8_t* data;
size_t remain;
int error;
};
void memread(void* buf, size_t size, size_t count, void* _data)
{
struct memdata* data = (struct memdata*)_data;
size_t unread = 0;
size *= count;
if (size > data->remain)
{
unread = size - data->remain;
size = data->remain;
data->error = 1;
}
memcpy(buf, data->data, size);
data->data += size;
data->remain -= size;
if (unread)
memset(((uint8_t*)buf) + size, 0, unread);
}
int memerror(void* _data)
{
struct memdata* data = (struct memdata*)_data;
return data->error;
}
void fileread(void* buf, size_t size, size_t count, void* _file)
{
FILE* file = (FILE*)_file;
fread(buf, size, count, file);
}
int fileerror(void* _file)
{
FILE* file = (FILE*)_file;
return ferror(file);
}
typedef void (*thereader)(void*, size_t, size_t, void*);
typedef int (*theerror)(void*);
//---------------------JXS3457
static int struct_readHeader(JT1Song* dest, thereader reader, theerror iferror, void* fin) {
f_JT1Header t;
reader(&t, sizeof(f_JT1Header), 1, fin);
dest->mugiversion = t.mugiversion;
dest->nrofpats = t.nrofpats;
dest->nrofsongs = t.nrofsongs;
dest->nrofinst = t.nrofinst;
return iferror(fin);
}
static int struct_readSubsong(JT1Subsong* dest, size_t len, thereader reader, theerror iferror, void* fin) {
uint32_t i, j, k;
f_JT1Subsong t;
for (i=0; i < len; i++) {
reader(&t, sizeof(f_JT1Subsong), 1, fin);
for (j=0; j < J3457_CHANS_SUBSONG; j++) dest[i].mute[j] = t.mute[j];
dest[i].songspd = t.songspd;
dest[i].groove = t.groove;
dest[i].songpos = t.songpos;
dest[i].songstep = t.songstep;
dest[i].endpos = t.endpos;
dest[i].endstep = t.endstep;
dest[i].looppos = t.looppos;
dest[i].loopstep = t.loopstep;
dest[i].songloop = t.songloop;
memcpy(&dest[i].name, &t.name, 32);
dest[i].nrofchans = t.nrofchans;
dest[i].delaytime = t.delaytime;
for (j=0; j < J3457_CHANS_SUBSONG; j++) {
dest[i].delayamount[j] = t.delayamount[j];
}
dest[i].amplification = t.amplification;
for (j=0; j < J3457_CHANS_SUBSONG; j++) {
for (k=0; k < J3457_ORDERS_SUBSONG; k++) {
dest[i].orders[j][k].patnr = t.orders[j][k].patnr;
dest[i].orders[j][k].patlen = t.orders[j][k].patlen;
}
}
}
return iferror(fin);
}
static int struct_readPat(JT1Row* dest, size_t len, thereader reader, theerror iferror, void* fin) {
uint32_t i, j;
f_JT1Row t[J3457_ROWS_PAT];
for (i=0; i < len; i++) {
reader(&t, sizeof(f_JT1Row)*J3457_ROWS_PAT, 1, fin);
for (j=0; j < J3457_ROWS_PAT; j++) {
uint32_t off = i*J3457_ROWS_PAT + j;
dest[off].srcnote = t[j].srcnote;
dest[off].dstnote = t[j].dstnote;
dest[off].inst = t[j].inst;
dest[off].param = t[j].param;
dest[off].script = t[j].script;
}
}
return iferror(fin);
}
static int struct_readInst(JT1Inst* dest, size_t len, thereader reader, theerror iferror, void* fin) {
uint32_t i, j;
f_JT1Inst t;
for (i=0; i < len; i++) {
reader(&t, sizeof(f_JT1Inst), 1, fin);
dest[i].mugiversion = t.mugiversion;
memcpy(&dest[i].instname, &t.instname, 32);
dest[i].waveform = t.waveform;
dest[i].wavelength = t.wavelength;
dest[i].mastervol = t.mastervol;
dest[i].amwave = t.amwave;
dest[i].amspd = t.amspd;
dest[i].amlooppoint = t.amlooppoint;
dest[i].finetune = t.finetune;
dest[i].fmwave = t.fmwave;
dest[i].fmspd = t.fmspd;
dest[i].fmlooppoint = t.fmlooppoint;
dest[i].fmdelay = t.fmdelay;
dest[i].arpeggio = t.arpeggio;
for (j=0; j < J3457_WAVES_INST; j++) {
dest[i].resetwave[j] = t.resetwave[j];
}
dest[i].panwave = t.panwave;
dest[i].panspd = t.panspd;
dest[i].panlooppoint = t.panlooppoint;
for (j=0; j < J3457_EFF_INST; j++) {
dest[i].fx[j].dsteffect = t.fx[j].dsteffect;
dest[i].fx[j].srceffect1 = t.fx[j].srceffect1;
dest[i].fx[j].srceffect2 = t.fx[j].srceffect2;
dest[i].fx[j].osceffect = t.fx[j].osceffect;
dest[i].fx[j].effectvar1 = t.fx[j].effectvar1;
dest[i].fx[j].effectvar2 = t.fx[j].effectvar2;
dest[i].fx[j].effectspd = t.fx[j].effectspd;
dest[i].fx[j].oscspd = t.fx[j].oscspd;
dest[i].fx[j].effecttype = t.fx[j].effecttype;
dest[i].fx[j].oscflg = t.fx[j].oscflg;
dest[i].fx[j].reseteffect = t.fx[j].reseteffect;
}
memcpy(&dest[i].samplename, &t.samplename, 192);
//exFnameFromPath(&dest[i].samplename, &t.samplename, SE_NAMELEN);
dest[i].sharing = t.sharing;
dest[i].loopflg = t.loopflg;
dest[i].bidirecflg = t.bidirecflg;
dest[i].startpoint = t.startpoint;
dest[i].looppoint = t.looppoint;
dest[i].endpoint = t.endpoint;
dest[i].hasSampData = t.hasSampData ? 1 : 0; //this was a sampdata pointer in original jaytrax
dest[i].samplelength = t.samplelength;
//memcpy(&dest[i].waves, &t.waves, J3457_WAVES_INST * J3457_SAMPS_WAVE * sizeof(int16_t));
reader(&dest->waves, 2, J3457_WAVES_INST * J3457_SAMPS_WAVE, fin);
}
return iferror(fin);
}
//---------------------JXS3458
/* Soon! */
//---------------------
static int jxsfile_readSongCb(thereader reader, theerror iferror, void* fin, JT1Song** sngOut) {
#define FAIL(x) {error=(x); goto _ERR;}
JT1Song* song;
int i;
int error;
//song
if((song = (JT1Song*)calloc(1, sizeof(JT1Song)))) {
int version;
if (struct_readHeader(song, reader, iferror, fin)) FAIL(ERR_BADSONG);
//version magic
version = song->mugiversion;
if (version >= 3456 && version <= 3457) {
int nrSubsongs = song->nrofsongs;
int nrPats = song->nrofpats;
int nrRows = J3457_ROWS_PAT * nrPats;
int nrInst = song->nrofinst;
//subsongs
if ((song->subsongs = (JT1Subsong**)calloc(nrSubsongs, sizeof(JT1Subsong*)))) {
for (i=0; i < nrSubsongs; i++) {
if ((song->subsongs[i] = (JT1Subsong*)calloc(1, sizeof(JT1Subsong)))) {
if (struct_readSubsong(song->subsongs[i], 1, reader, iferror, fin)) FAIL(ERR_BADSONG);
} else FAIL(ERR_MALLOC);
}
} else FAIL(ERR_MALLOC);
//patterns
if ((song->patterns = (JT1Row*)calloc(nrRows, sizeof(JT1Row)))) {
if (struct_readPat(song->patterns, nrPats, reader, iferror, fin)) FAIL(ERR_BADSONG);
} else FAIL(ERR_MALLOC);
//pattern names. Length includes \0
if ((song->patNames = (char**)calloc(nrPats, sizeof(char*)))) {
for (i=0; i < nrPats; i++) {
int32_t nameLen = 0;
reader(&nameLen, 4, 1, fin);
if ((song->patNames[i] = (char*)calloc(nameLen, sizeof(char)))) {
reader(song->patNames[i], nameLen, 1, fin);
} else FAIL(ERR_MALLOC);
}
if (iferror(fin)) FAIL(ERR_BADSONG);
} else FAIL(ERR_MALLOC);
//instruments
if ((song->instruments = (JT1Inst**)calloc(nrInst, sizeof(JT1Inst*)))) {
if (!(song->samples = (uint8_t**)calloc(nrInst, sizeof(uint8_t*)))) FAIL(ERR_MALLOC);
for (i=0; i < nrInst; i++) {
if ((song->instruments[i] = (JT1Inst*)calloc(1, sizeof(JT1Inst)))) {
JT1Inst* inst = song->instruments[i];
if (struct_readInst(inst, 1, reader, iferror, fin)) FAIL(ERR_BADSONG);
//patch old instrument to new
if (version == 3456) {
inst->sharing = 0;
inst->loopflg = 0;
inst->bidirecflg = 0;
inst->startpoint = 0;
inst->looppoint = 0;
inst->endpoint = 0;
//silly place to put a pointer
if (inst->hasSampData) {
inst->startpoint=0;
inst->endpoint=(inst->samplelength/2);
inst->looppoint=0;
}
}
//sample data
if (inst->hasSampData) {
//inst->samplelength is in bytes, not samples
if(!(song->samples[i] = (uint8_t*)calloc(inst->samplelength, sizeof(uint8_t)))) FAIL(ERR_MALLOC);
reader(song->samples[i], 1, inst->samplelength, fin);
if (iferror(fin)) FAIL(ERR_BADSONG);
} else {
song->samples[i] = NULL;
}
} else FAIL(ERR_MALLOC);
}
} else FAIL(ERR_MALLOC);
//arpeggio table
reader(&song->arpTable, J3457_STEPS_ARP, J3457_ARPS_SONG, fin);
if (iferror(fin)) FAIL(ERR_BADSONG);
} else if (version == 3458) {
//Soon enough!
FAIL(ERR_BADSONG);
} else FAIL(ERR_BADSONG);
} else FAIL(ERR_MALLOC);
*sngOut = song;
return ERR_OK;
#undef FAIL
_ERR:
jxsfile_freeSong(song);
*sngOut = NULL;
return error;
}
int jxsfile_readSong(const char* path, JT1Song** sngOut) {
char buf[BUFSIZ];
FILE *fin;
int error;
if (!(fin = fopen(path, "rb"))) return ERR_FILEIO;
setbuf(fin, buf);
error = jxsfile_readSongCb(fileread, fileerror, fin, sngOut);
fclose(fin);
return error;
_ERR:
if (fin) fclose(fin);
return error;
}
int jxsfile_readSongMem(const uint8_t* data, size_t size, JT1Song** sngOut) {
struct memdata fin;
fin.data = data;
fin.remain = size;
fin.error = 0;
return jxsfile_readSongCb(memread, memerror, &fin, sngOut);
}
void jxsfile_freeSong(JT1Song* song) {
if (song) {
int i;
int nrSubsongs = song->nrofsongs;
int nrPats = song->nrofpats;
int nrInst = song->nrofinst;
if (song->subsongs) {
for (i=0; i < nrSubsongs; i++) {
if (song->subsongs[i])
free(song->subsongs[i]);
}
free(song->subsongs);
}
if (song->patterns) {
free(song->patterns);
}
if (song->patNames) {
for (i=0; i < nrPats; i++) {
if (song->patNames[i])
free(song->patNames[i]);
}
free(song->patNames);
}
if (song->instruments && song->samples) {
for (i=0; i < nrInst; i++) {
if (song->instruments[i])
free(song->instruments[i]);
if (song->samples[i])
free(song->samples[i]);
}
}
if (song->samples) {
free(song->samples);
}
if (song->instruments) {
free(song->instruments);
}
free(song);
}
}