forked from len0rd/rockbox
Fixed warnings, adapted to Rockbox coding style, optimized to 78% realtime.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6329 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
74e9d545ef
commit
9ec1ff8cf5
7 changed files with 1056 additions and 1115 deletions
|
@ -21,197 +21,176 @@ extern struct plugin_api * rb;
|
||||||
|
|
||||||
unsigned int readWord(int file)
|
unsigned int readWord(int file)
|
||||||
{
|
{
|
||||||
return (readChar(file)<<0) | (readChar(file)<<8); // | (readChar(file)<<8) | (readChar(file)<<0);
|
return (readChar(file)<<0) | (readChar(file)<<8); // | (readChar(file)<<8) | (readChar(file)<<0);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int readDWord(int file)
|
unsigned int readDWord(int file)
|
||||||
{
|
{
|
||||||
return (readChar(file)<<0) | (readChar(file)<<8) | (readChar(file)<<16) | (readChar(file)<<24);
|
return (readChar(file)<<0) | (readChar(file)<<8) | (readChar(file)<<16) | (readChar(file)<<24);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GWaveform * loadWaveform(int file)
|
struct GWaveform * loadWaveform(int file)
|
||||||
{
|
{
|
||||||
struct GWaveform * wav = (struct GWaveform *)allocate(sizeof(struct GWaveform));
|
struct GWaveform * wav = (struct GWaveform *)allocate(sizeof(struct GWaveform));
|
||||||
rb->memset(wav, 0, sizeof(struct GWaveform));
|
rb->memset(wav, 0, sizeof(struct GWaveform));
|
||||||
|
|
||||||
wav->name=readData(file, 7);
|
wav->name=readData(file, 7);
|
||||||
printf("\nWAVE NAME = [%s]", wav->name);
|
printf("\nWAVE NAME = [%s]", wav->name);
|
||||||
wav->fractions=readChar(file);
|
wav->fractions=readChar(file);
|
||||||
wav->wavSize=readDWord(file);
|
wav->wavSize=readDWord(file);
|
||||||
wav->startLoop=readDWord(file);
|
wav->startLoop=readDWord(file);
|
||||||
wav->endLoop=readDWord(file);
|
wav->endLoop=readDWord(file);
|
||||||
wav->sampRate=readWord(file);
|
wav->sampRate=readWord(file);
|
||||||
|
|
||||||
wav->lowFreq=readDWord(file);
|
wav->lowFreq=readDWord(file);
|
||||||
wav->highFreq=readDWord(file);
|
wav->highFreq=readDWord(file);
|
||||||
wav->rootFreq=readDWord(file);
|
wav->rootFreq=readDWord(file);
|
||||||
|
|
||||||
wav->tune=readWord(file);
|
wav->tune=readWord(file);
|
||||||
|
|
||||||
wav->balance=readChar(file);
|
wav->balance=readChar(file);
|
||||||
wav->envRate=readData(file, 6);
|
wav->envRate=readData(file, 6);
|
||||||
wav->envOffset=readData(file, 6);
|
wav->envOffset=readData(file, 6);
|
||||||
|
|
||||||
wav->tremSweep=readChar(file);
|
wav->tremSweep=readChar(file);
|
||||||
wav->tremRate==readChar(file);
|
wav->tremRate==readChar(file);
|
||||||
wav->tremDepth=readChar(file);
|
wav->tremDepth=readChar(file);
|
||||||
wav->vibSweep=readChar(file);
|
wav->vibSweep=readChar(file);
|
||||||
wav->vibRate=readChar(file);
|
wav->vibRate=readChar(file);
|
||||||
wav->vibDepth=readChar(file);
|
wav->vibDepth=readChar(file);
|
||||||
wav->mode=readChar(file);
|
wav->mode=readChar(file);
|
||||||
|
|
||||||
wav->scaleFreq=readWord(file);
|
wav->scaleFreq=readWord(file);
|
||||||
wav->scaleFactor=readWord(file);
|
wav->scaleFactor=readWord(file);
|
||||||
printf("\nScaleFreq = %d ScaleFactor = %d RootFreq = %d", wav->scaleFreq, wav->scaleFactor, wav->rootFreq);
|
printf("\nScaleFreq = %d ScaleFactor = %d RootFreq = %d", wav->scaleFreq, wav->scaleFactor, wav->rootFreq);
|
||||||
wav->res=readData(file, 36);
|
wav->res=readData(file, 36);
|
||||||
wav->data=readData(file, wav->wavSize);
|
wav->data=readData(file, wav->wavSize);
|
||||||
|
|
||||||
wav->numSamples = wav->wavSize / 2;
|
wav->numSamples = wav->wavSize / 2;
|
||||||
int a=0;
|
wav->startLoop = wav->startLoop >> 1;
|
||||||
|
wav->endLoop = wav->endLoop >> 1;
|
||||||
|
unsigned int a=0;
|
||||||
|
|
||||||
return wav;
|
/* half baked 8 bit conversion UNFINISHED*/
|
||||||
if(wav->mode & 1 == 0) //Whoops, 8 bit
|
/*
|
||||||
{
|
if(wav->mode & 1 == 0) //Whoops, 8 bit
|
||||||
wav->numSamples = wav->wavSize;
|
{
|
||||||
|
wav->numSamples = wav->wavSize;
|
||||||
|
|
||||||
//Allocate a block for the rest of it
|
//Allocate a block for the rest of it
|
||||||
//It should end up right after the previous one.
|
//It should end up right after the previous one.
|
||||||
wav->wavSize = wav->wavSize * 2;
|
wav->wavSize = wav->wavSize * 2;
|
||||||
void * foo = allocate(wav->wavSize);
|
void * foo = allocate(wav->wavSize);
|
||||||
|
|
||||||
|
|
||||||
for(a=0; a<1000; a++)
|
for(a=0; a<1000; a++)
|
||||||
printf("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
printf("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||||
|
|
||||||
|
|
||||||
for(a=wav->wavSize-1; a>0; a-=2)
|
for(a=wav->wavSize-1; a>0; a-=2)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
// int b1=wf->data[s]+((wf->mode & 2) << 6);
|
// int b1=wf->data[s]+((wf->mode & 2) << 6);
|
||||||
// return b1<<8;
|
// return b1<<8;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
/*
|
|
||||||
//#if !defined(SIMULATOR)
|
|
||||||
for(a=0; a<wav->wavSize; a+=2)
|
|
||||||
{
|
|
||||||
unsigned char tmp;
|
|
||||||
tmp = wav->data[2*a];
|
|
||||||
wav->data[2*a] = wav->data[2*a+1];
|
|
||||||
wav->data[2*a+1] = tmp;
|
|
||||||
}
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
if(wav->mode & 2)
|
|
||||||
{
|
|
||||||
for(a=0; a<wav->wavSize/2; a++)
|
|
||||||
{
|
|
||||||
((short *) wav->data)[a] = ((short *) wav->data)[a] - 32767;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Iriver needs byteswapping.. big endian, go figure. Gus files are little endian */
|
||||||
|
|
||||||
//If we have a 16 bit waveform
|
#if !defined(SIMULATOR)
|
||||||
/* if(wav->mode & 1 && (wav->mode & 2))
|
for(a=0; a<wav->numSamples; a++)
|
||||||
{
|
{
|
||||||
for(a=0; a<wav->wavSize; a+=2) //Convert it to
|
((unsigned short *) wav->data)[a] = SWAB16(((unsigned short *) wav->data)[a]);
|
||||||
{
|
}
|
||||||
wav->data[a]=wav->data[a]+(1 << 7);
|
#endif
|
||||||
wav->data[a|1]=wav->data[(a)|1]+(1 << 7);
|
|
||||||
}
|
/* Convert unsigned to signed by subtracting 32768 */
|
||||||
}
|
if(wav->mode & 2)
|
||||||
*/
|
{
|
||||||
return wav;
|
for(a=0; a<wav->numSamples; a++)
|
||||||
|
((short *) wav->data)[a] = ((unsigned short *) wav->data)[a] - 32768;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return wav;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int selectWaveform(struct GPatch * pat, int midiNote)
|
int selectWaveform(struct GPatch * pat, int midiNote)
|
||||||
{
|
{
|
||||||
int tabFreq = gustable[midiNote]/100; //Comparison
|
/* We divide by 100 here because everyone's freq formula is slightly different */
|
||||||
int a=0;
|
unsigned int tabFreq = gustable[midiNote]/100; /* Comparison */
|
||||||
for(a=0; a<pat->numWaveforms; a++)
|
unsigned int a=0;
|
||||||
{
|
for(a=0; a<pat->numWaveforms; a++)
|
||||||
if(pat->waveforms[a]->lowFreq/100 <= tabFreq &&
|
{
|
||||||
pat->waveforms[a]->highFreq/100 >= tabFreq)
|
if(pat->waveforms[a]->lowFreq/100 <= tabFreq &&
|
||||||
{
|
pat->waveforms[a]->highFreq/100 >= tabFreq)
|
||||||
return a;
|
{
|
||||||
}
|
return a;
|
||||||
}
|
}
|
||||||
return 0;
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct GPatch * gusload(char * filename)
|
struct GPatch * gusload(char * filename)
|
||||||
{
|
{
|
||||||
struct GPatch * gp = (struct GPatch *)allocate(sizeof(struct GPatch));
|
struct GPatch * gp = (struct GPatch *)allocate(sizeof(struct GPatch));
|
||||||
rb->memset(gp, 0, sizeof(struct GPatch));
|
rb->memset(gp, 0, sizeof(struct GPatch));
|
||||||
|
|
||||||
int file = rb->open(filename, O_RDONLY);
|
int file = rb->open(filename, O_RDONLY);
|
||||||
|
|
||||||
if(file == -1)
|
if(file == -1)
|
||||||
{
|
{
|
||||||
char message[50];
|
char message[50];
|
||||||
rb->snprintf(message, 50, "Error opening %s", filename);
|
rb->snprintf(message, 50, "Error opening %s", filename);
|
||||||
rb->splash(HZ*2, true, message);
|
rb->splash(HZ*2, true, message);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
gp->header=readData(file, 12);
|
gp->header=readData(file, 12);
|
||||||
gp->gravisid=readData(file, 10);
|
gp->gravisid=readData(file, 10);
|
||||||
gp->desc=readData(file, 60);
|
gp->desc=readData(file, 60);
|
||||||
gp->inst=readChar(file);
|
gp->inst=readChar(file);
|
||||||
gp->voc=readChar(file);
|
gp->voc=readChar(file);
|
||||||
gp->chan=readChar(file);
|
gp->chan=readChar(file);
|
||||||
gp->numWaveforms=readWord(file); //readWord(file);
|
gp->numWaveforms=readWord(file);
|
||||||
gp->vol=readWord(file);
|
gp->vol=readWord(file);
|
||||||
gp->datSize=readDWord(file);
|
gp->datSize=readDWord(file);
|
||||||
gp->res=readData(file, 36);
|
gp->res=readData(file, 36);
|
||||||
|
|
||||||
gp->instrID=readWord(file);
|
gp->instrID=readWord(file);
|
||||||
gp->instrName=readData(file,16);
|
gp->instrName=readData(file,16);
|
||||||
gp->instrSize=readDWord(file);
|
gp->instrSize=readDWord(file);
|
||||||
gp->layers=readChar(file);
|
gp->layers=readChar(file);
|
||||||
gp->instrRes=readData(file,40);
|
gp->instrRes=readData(file,40);
|
||||||
|
|
||||||
|
|
||||||
gp->layerDup=readChar(file);
|
gp->layerDup=readChar(file);
|
||||||
gp->layerID=readChar(file);
|
gp->layerID=readChar(file);
|
||||||
gp->layerSize=readDWord(file);
|
gp->layerSize=readDWord(file);
|
||||||
gp->numWaves=readChar(file);
|
gp->numWaves=readChar(file);
|
||||||
gp->layerRes=readData(file,40);
|
gp->layerRes=readData(file,40);
|
||||||
|
|
||||||
/* printf("\n%s\n%s\n%s", gp->header, gp->gravisid, gp->desc);
|
|
||||||
printf("\nInst = %d", gp->inst);
|
|
||||||
printf("\nVoc = %d", gp->voc);
|
|
||||||
printf("\nChan = %d", gp->chan);
|
|
||||||
printf("\nWav = %d", gp->numWaveforms);
|
|
||||||
printf("\nVol = %d", gp->vol);
|
|
||||||
printf("\nSize = %d", gp->datSize);
|
|
||||||
|
|
||||||
printf("\n\ninstrID = %d", gp->instrID);
|
|
||||||
printf("\ninstrName = %s", gp->instrName);
|
|
||||||
// printf("\ninstrSize = %d", gp->instrSize);
|
|
||||||
// printf("\nlayers = %d", gp->layers);
|
|
||||||
*/
|
|
||||||
printf("\nFILE: %s", filename);
|
|
||||||
printf("\nlayerSamples=%d", gp->numWaves);
|
|
||||||
|
|
||||||
int a=0;
|
|
||||||
for(a=0; a<gp->numWaves; a++)
|
|
||||||
gp->waveforms[a] = loadWaveform(file);
|
|
||||||
|
|
||||||
|
|
||||||
printf("\nPrecomputing note table");
|
printf("\nFILE: %s", filename);
|
||||||
|
printf("\nlayerSamples=%d", gp->numWaves);
|
||||||
|
|
||||||
for(a=0; a<128; a++)
|
int a=0;
|
||||||
{
|
for(a=0; a<gp->numWaves; a++)
|
||||||
gp->noteTable[a] = selectWaveform(gp, a);
|
gp->waveforms[a] = loadWaveform(file);
|
||||||
}
|
|
||||||
rb->close(file);
|
|
||||||
|
|
||||||
return gp;
|
|
||||||
|
printf("\nPrecomputing note table");
|
||||||
|
|
||||||
|
for(a=0; a<128; a++)
|
||||||
|
{
|
||||||
|
gp->noteTable[a] = selectWaveform(gp, a);
|
||||||
|
}
|
||||||
|
rb->close(file);
|
||||||
|
|
||||||
|
return gp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
//This came from one of the Gravis documents
|
/* This came from one of the Gravis documents */
|
||||||
static const unsigned int gustable[]=
|
static const unsigned int gustable[]=
|
||||||
{
|
{
|
||||||
8175, 8661, 9177, 9722, 10300, 10913, 11562, 12249, 12978, 13750, 14567, 15433,
|
8175, 8661, 9177, 9722, 10300, 10913, 11562, 12249, 12978, 13750, 14567, 15433,
|
||||||
|
@ -33,63 +33,63 @@ static const unsigned int gustable[]=
|
||||||
|
|
||||||
struct GWaveform
|
struct GWaveform
|
||||||
{
|
{
|
||||||
unsigned char * name;
|
unsigned char * name;
|
||||||
unsigned char fractions;
|
unsigned char fractions;
|
||||||
unsigned int wavSize;
|
unsigned int wavSize;
|
||||||
unsigned int numSamples;
|
unsigned int numSamples;
|
||||||
unsigned int startLoop;
|
unsigned int startLoop;
|
||||||
unsigned int endLoop;
|
unsigned int endLoop;
|
||||||
unsigned int sampRate;
|
unsigned int sampRate;
|
||||||
unsigned int lowFreq;
|
unsigned int lowFreq;
|
||||||
unsigned int highFreq;
|
unsigned int highFreq;
|
||||||
unsigned int rootFreq;
|
unsigned int rootFreq;
|
||||||
unsigned int tune;
|
unsigned int tune;
|
||||||
unsigned int balance;
|
unsigned int balance;
|
||||||
unsigned char * envRate;
|
unsigned char * envRate;
|
||||||
unsigned char * envOffset;
|
unsigned char * envOffset;
|
||||||
|
|
||||||
unsigned char tremSweep;
|
unsigned char tremSweep;
|
||||||
unsigned char tremRate;
|
unsigned char tremRate;
|
||||||
unsigned char tremDepth;
|
unsigned char tremDepth;
|
||||||
unsigned char vibSweep;
|
unsigned char vibSweep;
|
||||||
unsigned char vibRate;
|
unsigned char vibRate;
|
||||||
unsigned char vibDepth;
|
unsigned char vibDepth;
|
||||||
unsigned char mode;
|
unsigned char mode;
|
||||||
|
|
||||||
unsigned int scaleFreq;
|
unsigned int scaleFreq;
|
||||||
unsigned int scaleFactor;
|
unsigned int scaleFactor;
|
||||||
|
|
||||||
unsigned char * res;
|
unsigned char * res;
|
||||||
signed char * data;
|
signed char * data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct GPatch
|
struct GPatch
|
||||||
{
|
{
|
||||||
unsigned int patchNumber;
|
unsigned int patchNumber;
|
||||||
unsigned char * header;
|
unsigned char * header;
|
||||||
unsigned char * gravisid;
|
unsigned char * gravisid;
|
||||||
unsigned char * desc;
|
unsigned char * desc;
|
||||||
unsigned char inst, voc, chan;
|
unsigned char inst, voc, chan;
|
||||||
unsigned int numWaveforms;
|
unsigned int numWaveforms;
|
||||||
unsigned int datSize;
|
unsigned int datSize;
|
||||||
unsigned int vol;
|
unsigned int vol;
|
||||||
unsigned char * res;
|
unsigned char * res;
|
||||||
|
|
||||||
|
|
||||||
unsigned int instrID;
|
unsigned int instrID;
|
||||||
unsigned char * instrName;
|
unsigned char * instrName;
|
||||||
unsigned int instrSize;
|
unsigned int instrSize;
|
||||||
unsigned int layers;
|
unsigned int layers;
|
||||||
unsigned char * instrRes;
|
unsigned char * instrRes;
|
||||||
|
|
||||||
unsigned char layerDup;
|
unsigned char layerDup;
|
||||||
unsigned char layerID;
|
unsigned char layerID;
|
||||||
unsigned int layerSize;
|
unsigned int layerSize;
|
||||||
unsigned char numWaves;
|
unsigned char numWaves;
|
||||||
unsigned char * layerRes;
|
unsigned char * layerRes;
|
||||||
|
|
||||||
unsigned char noteTable[128];
|
unsigned char noteTable[128];
|
||||||
struct GWaveform * waveforms[255];
|
struct GWaveform * waveforms[255];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,233 +26,232 @@ void bail(const char *);
|
||||||
|
|
||||||
struct MIDIfile * loadFile(char * filename)
|
struct MIDIfile * loadFile(char * filename)
|
||||||
{
|
{
|
||||||
struct MIDIfile * mf;
|
struct MIDIfile * mf;
|
||||||
int file = rb->open (filename, O_RDONLY);
|
int file = rb->open (filename, O_RDONLY);
|
||||||
|
|
||||||
if(file==0)
|
if(file==-1)
|
||||||
{
|
{
|
||||||
bail("Could not open file\n");
|
bail("Could not open file\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
mf = (struct MIDIfile*)allocate(sizeof(struct MIDIfile));
|
mf = (struct MIDIfile*)allocate(sizeof(struct MIDIfile));
|
||||||
|
|
||||||
if(mf==NULL)
|
if(mf==NULL)
|
||||||
{
|
{
|
||||||
rb->close(file);
|
rb->close(file);
|
||||||
bail("Could not allocate memory for MIDIfile struct\n");
|
bail("Could not allocate memory for MIDIfile struct\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
rb->memset(mf, 0, sizeof(struct MIDIfile));
|
rb->memset(mf, 0, sizeof(struct MIDIfile));
|
||||||
|
|
||||||
if(readID(file) != ID_MTHD)
|
if(readID(file) != ID_MTHD)
|
||||||
{
|
{
|
||||||
rb->close(file);
|
rb->close(file);
|
||||||
bail("Invalid file header chunk.");
|
bail("Invalid file header chunk.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(readFourBytes(file)!=6)
|
if(readFourBytes(file)!=6)
|
||||||
{
|
{
|
||||||
rb->close(file);
|
rb->close(file);
|
||||||
bail("Header chunk size invalid.");
|
bail("Header chunk size invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(readTwoBytes(file)==2)
|
if(readTwoBytes(file)==2)
|
||||||
{
|
{
|
||||||
rb->close(file);
|
rb->close(file);
|
||||||
bail("MIDI file type not supported");
|
bail("MIDI file type not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
mf->numTracks = readTwoBytes(file);
|
mf->numTracks = readTwoBytes(file);
|
||||||
mf->div = readTwoBytes(file);
|
mf->div = readTwoBytes(file);
|
||||||
|
|
||||||
int track=0;
|
int track=0;
|
||||||
|
|
||||||
printf("\nnumTracks=%d div=%d\nBegin reading track data\n", mf->numTracks, mf->div);
|
printf("\nnumTracks=%d div=%d\nBegin reading track data\n", mf->numTracks, mf->div);
|
||||||
|
|
||||||
// return;
|
|
||||||
|
|
||||||
|
|
||||||
while(! eof(file) && track < mf->numTracks)
|
while(! eof(file) && track < mf->numTracks)
|
||||||
{
|
{
|
||||||
unsigned char id = readID(file);
|
unsigned char id = readID(file);
|
||||||
|
|
||||||
|
|
||||||
if(id == ID_EOF)
|
if(id == ID_EOF)
|
||||||
{
|
{
|
||||||
if(mf->numTracks != track)
|
if(mf->numTracks != track)
|
||||||
{
|
{
|
||||||
printf("\nError: file claims to have %d tracks.\n I only see %d here.\n", mf->numTracks, track);
|
printf("\nError: file claims to have %d tracks.\n I only see %d here.\n", mf->numTracks, track);
|
||||||
mf->numTracks = track;
|
mf->numTracks = track;
|
||||||
}
|
}
|
||||||
return mf;
|
return mf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID_MTRK)
|
if(id == ID_MTRK)
|
||||||
{
|
{
|
||||||
mf->tracks[track] = readTrack(file);
|
mf->tracks[track] = readTrack(file);
|
||||||
//exit(0);
|
//exit(0);
|
||||||
track++;
|
track++;
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
printf("\n SKIPPING TRACK");
|
printf("\n SKIPPING TRACK");
|
||||||
int len = readFourBytes(file);
|
int len = readFourBytes(file);
|
||||||
while(--len)
|
while(--len)
|
||||||
readChar(file);
|
readChar(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mf;
|
return mf;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int rStatus = 0;
|
int rStatus = 0;
|
||||||
|
|
||||||
//Returns 0 if done, 1 if keep going
|
/* Returns 0 if done, 1 if keep going */
|
||||||
int readEvent(int file, void * dest)
|
int readEvent(int file, void * dest)
|
||||||
{
|
{
|
||||||
struct Event dummy;
|
struct Event dummy;
|
||||||
struct Event * ev = (struct Event *) dest;
|
struct Event * ev = (struct Event *) dest;
|
||||||
|
|
||||||
if(ev == NULL)
|
if(ev == NULL)
|
||||||
ev = &dummy; //If we are just counting events instead of loading them
|
ev = &dummy; /* If we are just counting events instead of loading them */
|
||||||
|
|
||||||
ev->delta = readVarData(file);
|
ev->delta = readVarData(file);
|
||||||
|
|
||||||
|
|
||||||
int t=readChar(file);
|
int t=readChar(file);
|
||||||
|
|
||||||
if((t&0x80) == 0x80) //if not a running status event
|
if((t&0x80) == 0x80) /* if not a running status event */
|
||||||
{
|
{
|
||||||
ev->status = t;
|
ev->status = t;
|
||||||
if(t == 0xFF)
|
if(t == 0xFF)
|
||||||
{
|
{
|
||||||
ev->d1 = readChar(file);
|
ev->d1 = readChar(file);
|
||||||
ev->len = readVarData(file);
|
ev->len = readVarData(file);
|
||||||
|
|
||||||
//Allocate and read in the data block
|
/* Allocate and read in the data block */
|
||||||
if(dest != NULL)
|
if(dest != NULL)
|
||||||
{
|
{
|
||||||
ev->evData = readData(file, ev->len);
|
ev->evData = readData(file, ev->len);
|
||||||
printf("\nDATA: <%s>", ev->evData);
|
printf("\nDATA: <%s>", ev->evData);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Don't allocate anything, just see how much it would tale
|
/*
|
||||||
//To make memory usage efficient
|
* Don't allocate anything, just see how much it would tale
|
||||||
|
* To make memory usage efficient
|
||||||
|
*/
|
||||||
|
unsigned int a=0;
|
||||||
|
for(a=0; a<ev->len; a++)
|
||||||
|
readChar(file); //Skip skip
|
||||||
|
}
|
||||||
|
|
||||||
int a=0;
|
if(ev->d1 == 0x2F)
|
||||||
for(a=0; a<ev->len; a++)
|
{
|
||||||
readChar(file); //Skip skip
|
return 0; /* Termination meta-event */
|
||||||
}
|
}
|
||||||
|
} else /* If part of a running status event */
|
||||||
|
{
|
||||||
|
rStatus = t;
|
||||||
|
ev->status = t;
|
||||||
|
ev->d1 = readChar(file);
|
||||||
|
|
||||||
if(ev->d1 == 0x2F)
|
if ( ((t & 0xF0) != 0xD0) && ((t & 0xF0) != 0xC0) && ((t & 0xF0) > 0x40) )
|
||||||
{
|
{
|
||||||
return 0; //Termination meta-event
|
ev->d2 = readChar(file);
|
||||||
}
|
} else
|
||||||
} else //If part of a running status event
|
ev->d2 = 127;
|
||||||
{
|
}
|
||||||
rStatus = t;
|
} else /* Running Status */
|
||||||
ev->status = t;
|
{
|
||||||
ev->d1 = readChar(file);
|
ev->status = rStatus;
|
||||||
|
ev->d1 = t;
|
||||||
if ( ((t & 0xF0) != 0xD0) && ((t & 0xF0) != 0xC0) && ((t & 0xF0) > 0x40) )
|
if ( ((rStatus & 0xF0) != 0xD0) && ((rStatus & 0xF0) != 0xC0) && ((rStatus & 0xF0) > 0x40) )
|
||||||
{
|
{
|
||||||
ev->d2 = readChar(file);
|
ev->d2 = readChar(file);
|
||||||
} else
|
} else
|
||||||
ev->d2 = 127;
|
ev->d2 = 127;
|
||||||
}
|
}
|
||||||
} else //Running Status
|
return 1;
|
||||||
{
|
|
||||||
ev->status = rStatus;
|
|
||||||
ev->d1 = t;
|
|
||||||
if ( ((rStatus & 0xF0) != 0xD0) && ((rStatus & 0xF0) != 0xC0) && ((rStatus & 0xF0) > 0x40) )
|
|
||||||
{
|
|
||||||
ev->d2 = readChar(file);
|
|
||||||
} else
|
|
||||||
ev->d2 = 127;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct Track * readTrack(int file)
|
struct Track * readTrack(int file)
|
||||||
{
|
{
|
||||||
struct Track * trk = (struct Track *)allocate(sizeof(struct Track));
|
struct Track * trk = (struct Track *)allocate(sizeof(struct Track));
|
||||||
rb->memset(trk, 0, sizeof(struct Track));
|
rb->memset(trk, 0, sizeof(struct Track));
|
||||||
|
|
||||||
trk->size = readFourBytes(file);
|
trk->size = readFourBytes(file);
|
||||||
trk->pos = 0;
|
trk->pos = 0;
|
||||||
trk->delta = 0;
|
trk->delta = 0;
|
||||||
|
|
||||||
int numEvents=0;
|
int numEvents=0;
|
||||||
|
|
||||||
int pos = rb->lseek(file, 0, SEEK_CUR);
|
int pos = rb->lseek(file, 0, SEEK_CUR);
|
||||||
|
|
||||||
while(readEvent(file, NULL)) //Memory saving technique
|
while(readEvent(file, NULL)) /* Memory saving technique */
|
||||||
numEvents++; //Attempt to read in events, count how many
|
numEvents++; /* Attempt to read in events, count how many */
|
||||||
//THEN allocate memory and read them in
|
/* THEN allocate memory and read them in */
|
||||||
rb->lseek(file, pos, SEEK_SET);
|
rb->lseek(file, pos, SEEK_SET);
|
||||||
|
|
||||||
int trackSize = (numEvents+1) * sizeof(struct Event);
|
int trackSize = (numEvents+1) * sizeof(struct Event);
|
||||||
void * dataPtr = allocate(trackSize);
|
void * dataPtr = allocate(trackSize);
|
||||||
trk->dataBlock = dataPtr;
|
trk->dataBlock = dataPtr;
|
||||||
|
|
||||||
numEvents=0;
|
numEvents=0;
|
||||||
|
|
||||||
while(readEvent(file, dataPtr))
|
while(readEvent(file, dataPtr))
|
||||||
{
|
{
|
||||||
if(trackSize < dataPtr-trk->dataBlock)
|
if(trackSize < dataPtr-trk->dataBlock)
|
||||||
{
|
{
|
||||||
printf("\nTrack parser memory out of bounds");
|
printf("\nTrack parser memory out of bounds");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
dataPtr+=sizeof(struct Event);
|
dataPtr+=sizeof(struct Event);
|
||||||
numEvents++;
|
numEvents++;
|
||||||
}
|
}
|
||||||
trk->numEvents = numEvents;
|
trk->numEvents = numEvents;
|
||||||
|
|
||||||
return trk;
|
return trk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int readID(int file)
|
int readID(int file)
|
||||||
{
|
{
|
||||||
char id[5];
|
char id[5];
|
||||||
id[4]=0;
|
id[4]=0;
|
||||||
BYTE a;
|
BYTE a;
|
||||||
|
|
||||||
for(a=0; a<4; a++)
|
for(a=0; a<4; a++)
|
||||||
id[a]=readChar(file);
|
id[a]=readChar(file);
|
||||||
if(eof(file))
|
if(eof(file))
|
||||||
{
|
{
|
||||||
printf("\End of file reached.");
|
printf("\End of file reached.");
|
||||||
return ID_EOF;
|
return ID_EOF;
|
||||||
}
|
}
|
||||||
if(rb->strcmp(id, "MThd")==0)
|
if(rb->strcmp(id, "MThd")==0)
|
||||||
return ID_MTHD;
|
return ID_MTHD;
|
||||||
if(rb->strcmp(id, "MTrk")==0)
|
if(rb->strcmp(id, "MTrk")==0)
|
||||||
return ID_MTRK;
|
return ID_MTRK;
|
||||||
return ID_UNKNOWN;
|
return ID_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int readFourBytes(int file)
|
int readFourBytes(int file)
|
||||||
{
|
{
|
||||||
int data=0;
|
int data=0;
|
||||||
BYTE a=0;
|
BYTE a=0;
|
||||||
for(a=0; a<4; a++)
|
for(a=0; a<4; a++)
|
||||||
data=(data<<8)+readChar(file);
|
data=(data<<8)+readChar(file);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
int readTwoBytes(int file)
|
int readTwoBytes(int file)
|
||||||
{
|
{
|
||||||
int data=(readChar(file)<<8)+readChar(file);
|
int data=(readChar(file)<<8)+readChar(file);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
//This came from the MIDI file format guide
|
/* This came from the MIDI file format guide */
|
||||||
int readVarData(int file)
|
int readVarData(int file)
|
||||||
{
|
{
|
||||||
unsigned int value;
|
unsigned int value;
|
||||||
|
@ -270,37 +269,35 @@ int readVarData(int file)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
//This function should not be needed because we
|
|
||||||
//can just release the whole memory buffer at once
|
|
||||||
void unloadFile(struct MIDIfile * mf)
|
void unloadFile(struct MIDIfile * mf)
|
||||||
{
|
{
|
||||||
if(mf == NULL)
|
if(mf == NULL)
|
||||||
return;
|
return;
|
||||||
int a=0;
|
int a=0;
|
||||||
//Unload each track
|
//Unload each track
|
||||||
for(a=0; a<mf->numTracks; a++)
|
for(a=0; a<mf->numTracks; a++)
|
||||||
{
|
{
|
||||||
int b=0;
|
int b=0;
|
||||||
|
|
||||||
if(mf->tracks[a] != NULL)
|
if(mf->tracks[a] != NULL)
|
||||||
for(b=0; b<mf->tracks[a]->numEvents; b++)
|
for(b=0; b<mf->tracks[a]->numEvents; b++)
|
||||||
{
|
{
|
||||||
if(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData!=NULL)
|
if(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData!=NULL)
|
||||||
free(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData);
|
free(((struct Event*)((mf->tracks[a]->dataBlock)+b*sizeof(struct Event)))->evData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mf->tracks[a]!=NULL && mf->tracks[a]->dataBlock != NULL)
|
if(mf->tracks[a]!=NULL && mf->tracks[a]->dataBlock != NULL)
|
||||||
free(mf->tracks[a]->dataBlock); //Unload the event block
|
free(mf->tracks[a]->dataBlock); //Unload the event block
|
||||||
|
|
||||||
if(mf->tracks[a]!=NULL)
|
if(mf->tracks[a]!=NULL)
|
||||||
free(mf->tracks[a]); //Unload the track structure itself
|
free(mf->tracks[a]); //Unload the track structure itself
|
||||||
}
|
}
|
||||||
free(mf); //Unload the main struct
|
free(mf); //Unload the main struct
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
void bail(const char * err)
|
void bail(const char * err)
|
||||||
{
|
{
|
||||||
rb->splash(HZ*3, true, err);
|
rb->splash(HZ*3, true, err);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,39 +20,39 @@
|
||||||
#define BYTE unsigned char
|
#define BYTE unsigned char
|
||||||
|
|
||||||
//Data chunk ID types, returned by readID()
|
//Data chunk ID types, returned by readID()
|
||||||
#define ID_UNKNOWN -1
|
#define ID_UNKNOWN -1
|
||||||
#define ID_MTHD 1
|
#define ID_MTHD 1
|
||||||
#define ID_MTRK 2
|
#define ID_MTRK 2
|
||||||
#define ID_EOF 3
|
#define ID_EOF 3
|
||||||
|
|
||||||
//MIDI Commands
|
//MIDI Commands
|
||||||
#define MIDI_NOTE_OFF 128
|
#define MIDI_NOTE_OFF 128
|
||||||
#define MIDI_NOTE_ON 144
|
#define MIDI_NOTE_ON 144
|
||||||
#define MIDI_AFTERTOUCH 160
|
#define MIDI_AFTERTOUCH 160
|
||||||
#define MIDI_CONTROL 176
|
#define MIDI_CONTROL 176
|
||||||
#define MIDI_PRGM 192
|
#define MIDI_PRGM 192
|
||||||
#define MIDI_PITCHW 224
|
#define MIDI_PITCHW 224
|
||||||
|
|
||||||
|
|
||||||
//MIDI Controllers
|
//MIDI Controllers
|
||||||
#define CTRL_VOLUME 7
|
#define CTRL_VOLUME 7
|
||||||
#define CTRL_BALANCE 8
|
#define CTRL_BALANCE 8
|
||||||
#define CTRL_PANNING 10
|
#define CTRL_PANNING 10
|
||||||
#define CHANNEL 1
|
#define CHANNEL 1
|
||||||
|
|
||||||
//Most of these are deprecated.. rampdown is used, maybe one other one too
|
//Most of these are deprecated.. rampdown is used, maybe one other one too
|
||||||
#define STATE_ATTACK 1
|
#define STATE_ATTACK 1
|
||||||
#define STATE_DECAY 2
|
#define STATE_DECAY 2
|
||||||
#define STATE_SUSTAIN 3
|
#define STATE_SUSTAIN 3
|
||||||
#define STATE_RELEASE 4
|
#define STATE_RELEASE 4
|
||||||
#define STATE_RAMPDOWN 5
|
#define STATE_RAMPDOWN 5
|
||||||
|
|
||||||
//Loop states
|
//Loop states
|
||||||
#define STATE_LOOPING 7
|
#define STATE_LOOPING 7
|
||||||
#define STATE_NONLOOPING 8
|
#define STATE_NONLOOPING 8
|
||||||
|
|
||||||
//Various bits in the GUS mode byte
|
//Various bits in the GUS mode byte
|
||||||
#define LOOP_ENABLED 4
|
#define LOOP_ENABLED 4
|
||||||
#define LOOP_PINGPONG 8
|
#define LOOP_PINGPONG 8
|
||||||
#define LOOP_REVERSE 16
|
#define LOOP_REVERSE 16
|
||||||
|
|
||||||
|
@ -63,81 +63,69 @@
|
||||||
extern struct plugin_api * rb;
|
extern struct plugin_api * rb;
|
||||||
|
|
||||||
|
|
||||||
int chVol[16] IDATA_ATTR; //Channel volume
|
int chVol[16] IDATA_ATTR; /* Channel volume */
|
||||||
int chPanLeft[16] IDATA_ATTR; //Channel panning
|
int chPanLeft[16] IDATA_ATTR; /* Channel panning */
|
||||||
int chPanRight[16] IDATA_ATTR;
|
int chPanRight[16] IDATA_ATTR;
|
||||||
int chPat[16]; //Channel patch
|
int chPat[16]; /* Channel patch */
|
||||||
int chPW[16]; //Channel pitch wheel, MSB only
|
int chPW[16]; /* Channel pitch wheel, MSB only */
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
unsigned char chVol[16]; //Channel volume
|
|
||||||
unsigned char chPanLeft[16]; //Channel panning
|
|
||||||
unsigned char chPanRight[16];
|
|
||||||
unsigned char chPat[16]; //Channel patch
|
|
||||||
unsigned char chPW[16]; //Channel pitch wheel, MSB only
|
|
||||||
*/
|
|
||||||
struct GPatch * gusload(char *);
|
struct GPatch * gusload(char *);
|
||||||
struct GPatch * patchSet[128];
|
struct GPatch * patchSet[128];
|
||||||
struct GPatch * drumSet[128];
|
struct GPatch * drumSet[128];
|
||||||
|
|
||||||
|
|
||||||
//char myarray[80] IDATA_ATTR;
|
|
||||||
|
|
||||||
struct Event
|
struct Event
|
||||||
{
|
{
|
||||||
unsigned int delta;
|
unsigned int delta;
|
||||||
unsigned char status, d1, d2;
|
unsigned char status, d1, d2;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
unsigned char * evData;
|
unsigned char * evData;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Track
|
struct Track
|
||||||
{
|
{
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
unsigned int numEvents;
|
unsigned int numEvents;
|
||||||
unsigned int delta; //For sequencing
|
unsigned int delta; /* For sequencing */
|
||||||
unsigned int pos; //For sequencing
|
unsigned int pos; /* For sequencing */
|
||||||
void * dataBlock;
|
void * dataBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct MIDIfile
|
struct MIDIfile
|
||||||
{
|
{
|
||||||
int Length;
|
int Length;
|
||||||
|
unsigned short numTracks;
|
||||||
//int Format; //We don't really care what type it is
|
unsigned short div; /* Time division, X ticks per millisecond */
|
||||||
unsigned short numTracks;
|
struct Track * tracks[48];
|
||||||
unsigned short div; //Time division, X ticks per millisecond
|
unsigned char patches[128];
|
||||||
struct Track * tracks[48];
|
int numPatches;
|
||||||
unsigned char patches[128];
|
|
||||||
int numPatches;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct SynthObject
|
struct SynthObject
|
||||||
{
|
{
|
||||||
// int tmp;
|
struct GWaveform * wf;
|
||||||
struct GWaveform * wf;
|
unsigned int delta;
|
||||||
unsigned int delta;
|
unsigned int decay;
|
||||||
unsigned int decay;
|
unsigned int cp;
|
||||||
unsigned int cp;
|
unsigned char state, loopState, loopDir;
|
||||||
unsigned char state, loopState, loopDir;
|
unsigned char note, vol, ch, isUsed;
|
||||||
unsigned char note, vol, ch, isUsed;
|
int curRate, curOffset, targetOffset;
|
||||||
int curRate, curOffset, targetOffset;
|
unsigned int curPoint;
|
||||||
unsigned int curPoint;
|
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct SynthObject
|
struct SynthObject
|
||||||
{
|
{
|
||||||
// int tmp;
|
struct GWaveform * wf;
|
||||||
struct GWaveform * wf;
|
int delta;
|
||||||
int delta;
|
int decay;
|
||||||
int decay;
|
unsigned int cp;
|
||||||
int cp;
|
int state, loopState, loopDir;
|
||||||
int state, loopState, loopDir;
|
int note, vol, ch, isUsed;
|
||||||
int note, vol, ch, isUsed;
|
int curRate, curOffset, targetOffset;
|
||||||
int curRate, curOffset, targetOffset;
|
int curPoint;
|
||||||
int curPoint;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SynthObject voices[MAX_VOICES] IDATA_ATTR;
|
struct SynthObject voices[MAX_VOICES] IDATA_ATTR;
|
||||||
|
@ -156,91 +144,91 @@ int midimain(void * filename);
|
||||||
|
|
||||||
void *alloc(int size)
|
void *alloc(int size)
|
||||||
{
|
{
|
||||||
static char *offset = NULL;
|
static char *offset = NULL;
|
||||||
static int totalSize = 0;
|
static int totalSize = 0;
|
||||||
char *ret;
|
char *ret;
|
||||||
|
|
||||||
int remainder = size % 4;
|
int remainder = size % 4;
|
||||||
|
|
||||||
size = size + 4-remainder;
|
size = size + 4-remainder;
|
||||||
|
|
||||||
if (offset == NULL)
|
if (offset == NULL)
|
||||||
{
|
{
|
||||||
offset = rb->plugin_get_audio_buffer(&totalSize);
|
offset = rb->plugin_get_audio_buffer(&totalSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size + 4 > totalSize)
|
if (size + 4 > totalSize)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = offset + 4;
|
ret = offset + 4;
|
||||||
*((unsigned int *)offset) = size;
|
*((unsigned int *)offset) = size;
|
||||||
|
|
||||||
offset += size + 4;
|
offset += size + 4;
|
||||||
totalSize -= size + 4;
|
totalSize -= size + 4;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Rick's code
|
/* Rick's code */
|
||||||
/*
|
/*
|
||||||
void *alloc(int size)
|
void *alloc(int size)
|
||||||
{
|
{
|
||||||
static char *offset = NULL;
|
static char *offset = NULL;
|
||||||
static int totalSize = 0;
|
static int totalSize = 0;
|
||||||
char *ret;
|
char *ret;
|
||||||
|
|
||||||
|
|
||||||
if (offset == NULL)
|
if (offset == NULL)
|
||||||
{
|
{
|
||||||
offset = rb->plugin_get_audio_buffer(&totalSize);
|
offset = rb->plugin_get_audio_buffer(&totalSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size + 4 > totalSize)
|
if (size + 4 > totalSize)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = offset + 4;
|
ret = offset + 4;
|
||||||
*((unsigned int *)offset) = size;
|
*((unsigned int *)offset) = size;
|
||||||
|
|
||||||
offset += size + 4;
|
offset += size + 4;
|
||||||
totalSize -= size + 4;
|
totalSize -= size + 4;
|
||||||
return ret;
|
return ret;
|
||||||
}*/
|
}*/
|
||||||
void * allocate(int size)
|
void * allocate(int size)
|
||||||
{
|
{
|
||||||
return alloc(size);
|
return alloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char readChar(int file)
|
unsigned char readChar(int file)
|
||||||
{
|
{
|
||||||
char buf[2];
|
char buf[2];
|
||||||
rb->read(file, &buf, 1);
|
rb->read(file, &buf, 1);
|
||||||
return buf[0];
|
return buf[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char * readData(int file, int len)
|
unsigned char * readData(int file, int len)
|
||||||
{
|
{
|
||||||
unsigned char * dat = allocate(len);
|
unsigned char * dat = allocate(len);
|
||||||
rb->read(file, dat, len);
|
rb->read(file, dat, len);
|
||||||
return dat;
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
int eof(int fd)
|
int eof(int fd)
|
||||||
{
|
{
|
||||||
int curPos = rb->lseek(fd, 0, SEEK_CUR);
|
int curPos = rb->lseek(fd, 0, SEEK_CUR);
|
||||||
|
|
||||||
int size = rb->lseek(fd, 0, SEEK_END);
|
int size = rb->lseek(fd, 0, SEEK_END);
|
||||||
|
|
||||||
rb->lseek(fd, curPos, SEEK_SET);
|
rb->lseek(fd, curPos, SEEK_SET);
|
||||||
return size+1 == rb->lseek(fd, 0, SEEK_CUR);
|
return size+1 == rb->lseek(fd, 0, SEEK_CUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printf(char *fmt, ...) {fmt=fmt; }
|
void printf(char *fmt, ...) {fmt=fmt; }
|
||||||
|
|
||||||
void exit(int code)
|
void exit(int code)
|
||||||
{
|
{
|
||||||
code = code; //Stub function, kill warning for now
|
code = code; /* Stub function, kill warning for now */
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,233 +24,220 @@ long tempo=375000;
|
||||||
|
|
||||||
void setVol(int ch, int vol)
|
void setVol(int ch, int vol)
|
||||||
{
|
{
|
||||||
printf("\nvolume[%d] %d ==> %d", ch, chVol[ch], vol);
|
printf("\nvolume[%d] %d ==> %d", ch, chVol[ch], vol);
|
||||||
chVol[ch]=vol;
|
chVol[ch]=vol;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPan(int ch, int pan)
|
void setPan(int ch, int pan)
|
||||||
{
|
{
|
||||||
printf("\npanning[%d] %d ==> %d", ch, chPanRight[ch], pan);
|
printf("\npanning[%d] %d ==> %d", ch, chPanRight[ch], pan);
|
||||||
|
|
||||||
chPanLeft[ch]=128-pan;
|
chPanLeft[ch]=128-pan;
|
||||||
chPanRight[ch]=pan;
|
chPanRight[ch]=pan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setPatch(int ch, int pat)
|
void setPatch(int ch, int pat)
|
||||||
{
|
{
|
||||||
chPat[ch]=pat;
|
chPat[ch]=pat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Pitch Bend table, Computed by
|
* Pitch Bend table, Computed by
|
||||||
for i=0:127, fprintf('%d,', round(2^16*2^((i-64)/384))); end
|
* for i=0:127, fprintf('%d,', round(2^16*2^((i-64)/384))); end
|
||||||
(When typed into Matlab)
|
* (When typed into Matlab)
|
||||||
16 bit pitch bend table
|
* 16 bit pitch bend table
|
||||||
*/
|
*/
|
||||||
long pitchTbl[]=
|
long pitchTbl[]=
|
||||||
{
|
{
|
||||||
58386,58491,58597,58703,58809,58915,59022,59128,59235,59342,59449,59557,59664,59772,59880,59988,60097,60205,
|
58386,58491,58597,58703,58809,58915,59022,59128,59235,59342,59449,59557,59664,59772,59880,59988,60097,60205,
|
||||||
60314,60423,60532,60642,60751,60861,60971,61081,61191,61302,61413,61524,61635,61746,61858,61970,62081,62194,
|
60314,60423,60532,60642,60751,60861,60971,61081,61191,61302,61413,61524,61635,61746,61858,61970,62081,62194,
|
||||||
62306,62419,62531,62644,62757,62871,62984,63098,63212,63326,63441,63555,63670,63785,63901,64016,64132,64248,
|
62306,62419,62531,62644,62757,62871,62984,63098,63212,63326,63441,63555,63670,63785,63901,64016,64132,64248,
|
||||||
64364,64480,64596,64713,64830,64947,65065,65182,65300,65418,65536,65654,65773,65892,66011,66130,66250,66369,
|
64364,64480,64596,64713,64830,64947,65065,65182,65300,65418,65536,65654,65773,65892,66011,66130,66250,66369,
|
||||||
66489,66609,66730,66850,66971,67092,67213,67335,67456,67578,67700,67823,67945,68068,68191,68314,68438,68561,
|
66489,66609,66730,66850,66971,67092,67213,67335,67456,67578,67700,67823,67945,68068,68191,68314,68438,68561,
|
||||||
68685,68809,68933,69058,69183,69308,69433,69558,69684,69810,69936,70062,70189,70316,70443,70570,70698,70825,
|
68685,68809,68933,69058,69183,69308,69433,69558,69684,69810,69936,70062,70189,70316,70443,70570,70698,70825,
|
||||||
70953,71082,71210,71339,71468,71597,71726,71856,71985,72115,72246,72376,72507,72638,72769,72901,73032,73164,
|
70953,71082,71210,71339,71468,71597,71726,71856,71985,72115,72246,72376,72507,72638,72769,72901,73032,73164,
|
||||||
73297,73429
|
73297,73429
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void findDelta(struct SynthObject * so, int ch, int note)
|
void findDelta(struct SynthObject * so, int ch, int note)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct GWaveform * wf = patchSet[chPat[ch]]->waveforms[patchSet[chPat[ch]]->noteTable[note]];
|
struct GWaveform * wf = patchSet[chPat[ch]]->waveforms[patchSet[chPat[ch]]->noteTable[note]];
|
||||||
so->wf=wf;
|
so->wf=wf;
|
||||||
so->delta = (((gustable[note]<<10) / wf->rootFreq) * wf->sampRate / SAMPLE_RATE);
|
so->delta = (((gustable[note]<<10) / (wf->rootFreq)) * wf->sampRate / (SAMPLE_RATE));
|
||||||
so->delta = so->delta * pitchTbl[chPW[ch]] >> 16;
|
so->delta = (so->delta * pitchTbl[chPW[ch]])>> 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPW(int ch, int msb)
|
void setPW(int ch, int msb)
|
||||||
{
|
{
|
||||||
printf("\npitchw[%d] %d ==> %d", ch, chPW[ch], msb);
|
printf("\npitchw[%d] %d ==> %d", ch, chPW[ch], msb);
|
||||||
chPW[ch] = msb;
|
chPW[ch] = msb;
|
||||||
|
|
||||||
int a=0;
|
int a=0;
|
||||||
for(a = 0; a<MAX_VOICES; a++)
|
for(a = 0; a<MAX_VOICES; a++)
|
||||||
{
|
{
|
||||||
if(voices[a].isUsed==1 && voices[a].ch == ch)
|
if(voices[a].isUsed==1 && voices[a].ch == ch)
|
||||||
{
|
{
|
||||||
findDelta(&voices[a], ch, voices[a].note);
|
findDelta(&voices[a], ch, voices[a].note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pressNote(int ch, int note, int vol)
|
void pressNote(int ch, int note, int vol)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//Silences all channels but one, for easy debugging, for me.
|
||||||
/*
|
/*
|
||||||
if(ch == 0) return;
|
if(ch == 0) return;
|
||||||
// if(ch == 1) return;
|
if(ch == 1) return;
|
||||||
if(ch == 2) return;
|
if(ch == 2) return;
|
||||||
if(ch == 3) return;
|
if(ch == 3) return;
|
||||||
if(ch == 4) return;
|
// if(ch == 4) return;
|
||||||
if(ch == 5) return;
|
if(ch == 5) return;
|
||||||
if(ch == 6) return;
|
if(ch == 6) return;
|
||||||
if(ch == 7) return;
|
if(ch == 7) return;
|
||||||
if(ch == 8) return;
|
if(ch == 8) return;
|
||||||
if(ch == 9) return;
|
if(ch == 9) return;
|
||||||
if(ch == 10) return;
|
if(ch == 10) return;
|
||||||
if(ch == 11) return;
|
if(ch == 11) return;
|
||||||
if(ch == 12) return;
|
if(ch == 12) return;
|
||||||
if(ch == 13) return;
|
if(ch == 13) return;
|
||||||
if(ch == 14) return;
|
if(ch == 14) return;
|
||||||
if(ch == 15) return;
|
if(ch == 15) return;
|
||||||
*/
|
*/
|
||||||
int a=0;
|
int a=0;
|
||||||
for(a=0; a<MAX_VOICES; a++)
|
for(a=0; a<MAX_VOICES; a++)
|
||||||
{
|
{
|
||||||
if(voices[a].ch == ch && voices[a].note == note)
|
if(voices[a].ch == ch && voices[a].note == note)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(voices[a].isUsed==0)
|
if(voices[a].isUsed==0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(a==MAX_VOICES-1)
|
if(a==MAX_VOICES-1)
|
||||||
{
|
{
|
||||||
printf("\nOVERFLOW: Too many voices playing at once. No more left");
|
printf("\nOVERFLOW: Too many voices playing at once. No more left");
|
||||||
printf("\nVOICE DUMP: ");
|
printf("\nVOICE DUMP: ");
|
||||||
for(a=0; a<48; a++)
|
for(a=0; a<48; a++)
|
||||||
printf("\n#%d Ch=%d Note=%d curRate=%d curOffset=%d curPoint=%d targetOffset=%d", a, voices[a].ch, voices[a].note, voices[a].curRate, voices[a].curOffset, voices[a].curPoint, voices[a].targetOffset);
|
printf("\n#%d Ch=%d Note=%d curRate=%d curOffset=%d curPoint=%d targetOffset=%d", a, voices[a].ch, voices[a].note, voices[a].curRate, voices[a].curOffset, voices[a].curPoint, voices[a].targetOffset);
|
||||||
return; //None avaolable
|
return; /* None available */
|
||||||
}
|
}
|
||||||
voices[a].ch=ch;
|
voices[a].ch=ch;
|
||||||
voices[a].note=note;
|
voices[a].note=note;
|
||||||
voices[a].vol=vol;
|
voices[a].vol=vol;
|
||||||
voices[a].cp=0;
|
voices[a].cp=0;
|
||||||
voices[a].state=STATE_ATTACK;
|
voices[a].state=STATE_ATTACK;
|
||||||
// voices[a].pstate=STATE_ATTACK;
|
voices[a].decay=255;
|
||||||
voices[a].decay=255;
|
|
||||||
|
|
||||||
|
|
||||||
voices[a].loopState=STATE_NONLOOPING;
|
voices[a].loopState=STATE_NONLOOPING;
|
||||||
voices[a].loopDir = LOOPDIR_FORWARD;
|
voices[a].loopDir = LOOPDIR_FORWARD;
|
||||||
/*
|
/*
|
||||||
OKAY. Gt = Gus Table value
|
* OKAY. Gt = Gus Table value
|
||||||
rf = Root Frequency of wave
|
* rf = Root Frequency of wave
|
||||||
SR = sound sampling rate
|
* SR = sound sampling rate
|
||||||
sr = WAVE sampling rate
|
* sr = WAVE sampling rate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if(ch!=9)
|
||||||
|
{
|
||||||
|
findDelta(&voices[a], ch, note);
|
||||||
|
/* Turn it on */
|
||||||
|
voices[a].isUsed=1;
|
||||||
|
setPoint(&voices[a], 0);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if(drumSet[note]!=NULL)
|
||||||
|
{
|
||||||
|
if(note<35)
|
||||||
|
printf("\nNOTE LESS THAN 35, AND A DRUM PATCH EXISTS FOR THIS? WHAT THE HELL?");
|
||||||
|
|
||||||
/*
|
struct GWaveform * wf = drumSet[note]->waveforms[0];
|
||||||
unsigned int gt = gustable[note];
|
voices[a].wf=wf;
|
||||||
unsigned int rf = wf->rootFreq;
|
voices[a].delta = (((gustable[note]<<10) / wf->rootFreq) * wf->sampRate / SAMPLE_RATE);
|
||||||
unsigned int SR = SAMPLE_RATE;
|
if(wf->mode & 28)
|
||||||
unsigned int sr = wf->sampRate;
|
printf("\nWoah, a drum patch has a loop. Stripping the loop...");
|
||||||
voices[a].delta=((((gt<<10) / rf) * sr / SR));
|
wf->mode = wf->mode & (255-28);
|
||||||
*/
|
|
||||||
|
|
||||||
|
/* Turn it on */
|
||||||
|
voices[a].isUsed=1;
|
||||||
|
setPoint(&voices[a], 0);
|
||||||
|
|
||||||
if(ch!=9)
|
} else
|
||||||
{
|
{
|
||||||
findDelta(&voices[a], ch, note);
|
printf("\nWarning: drum %d does not have a patch defined... Ignoring it", note);
|
||||||
//Turn it on
|
}
|
||||||
voices[a].isUsed=1;
|
}
|
||||||
setPoint(&voices[a], 0);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
if(drumSet[note]!=NULL)
|
|
||||||
{
|
|
||||||
if(note<35)
|
|
||||||
printf("\nNOTE LESS THAN 35, AND A DRUM PATCH EXISTS FOR THIS? WHAT THE HELL?");
|
|
||||||
|
|
||||||
struct GWaveform * wf = drumSet[note]->waveforms[0];
|
|
||||||
voices[a].wf=wf;
|
|
||||||
voices[a].delta = (((gustable[note]<<10) / wf->rootFreq) * wf->sampRate / SAMPLE_RATE);
|
|
||||||
if(wf->mode & 28)
|
|
||||||
printf("\nWoah, a drum patch has a loop. Stripping the loop...");
|
|
||||||
wf->mode = wf->mode & (255-28);
|
|
||||||
//Turn it on
|
|
||||||
voices[a].isUsed=1;
|
|
||||||
setPoint(&voices[a], 0);
|
|
||||||
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
printf("\nWarning: drum %d does not have a patch defined... Ignoring it", note);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void releaseNote(int ch, int note)
|
void releaseNote(int ch, int note)
|
||||||
{
|
{
|
||||||
if(ch==9) // && note != 27 && note != 31 && note != 28)
|
if(ch==9)
|
||||||
return;
|
return;
|
||||||
int a=0;
|
|
||||||
for(a=0; a<MAX_VOICES; a++)
|
|
||||||
{
|
|
||||||
if(voices[a].ch == ch && voices[a].note == note)
|
|
||||||
{
|
|
||||||
if((voices[a].wf->mode & 28))
|
|
||||||
{
|
|
||||||
// voices[a].tmp=40;
|
|
||||||
// voices[a].state = STATE_RELEASE; //Ramp down
|
|
||||||
|
|
||||||
// voices[a].state = STATE_RAMPDOWN; //Ramp down
|
int a=0;
|
||||||
setPoint(&voices[a], 3);
|
for(a=0; a<MAX_VOICES; a++)
|
||||||
}
|
{
|
||||||
}
|
if(voices[a].ch == ch && voices[a].note == note)
|
||||||
}
|
{
|
||||||
|
if((voices[a].wf->mode & 28))
|
||||||
|
{
|
||||||
|
setPoint(&voices[a], 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendEvent(struct Event * ev)
|
void sendEvent(struct Event * ev)
|
||||||
{
|
{
|
||||||
// printf("\nEVENT S=%2x D1=%2x D2=%2x", ev->status, ev->d1, ev->d2);
|
if( ((ev->status & 0xF0) == MIDI_CONTROL) && (ev->d1 == CTRL_VOLUME) )
|
||||||
|
{
|
||||||
|
setVol((ev->status & 0xF), ev->d2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if( ((ev->status & 0xF0) == MIDI_CONTROL) && (ev->d1 == CTRL_VOLUME) )
|
if( ((ev->status & 0xF0) == MIDI_CONTROL) && (ev->d1 == CTRL_PANNING))
|
||||||
{
|
{
|
||||||
setVol((ev->status & 0xF), ev->d2);
|
setPan((ev->status & 0xF), ev->d2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ((ev->status & 0xF0) == MIDI_CONTROL) && (ev->d1 == CTRL_PANNING))
|
if(((ev->status & 0xF0) == MIDI_PITCHW))
|
||||||
{
|
{
|
||||||
setPan((ev->status & 0xF), ev->d2);
|
setPW((ev->status & 0xF), ev->d2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(((ev->status & 0xF0) == MIDI_PITCHW))
|
if(((ev->status & 0xF0) == MIDI_NOTE_ON) && (ev->d2 != 0))
|
||||||
{
|
{
|
||||||
setPW((ev->status & 0xF), ev->d2);
|
pressNote(ev->status & 0x0F, ev->d1, ev->d2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(((ev->status & 0xF0) == MIDI_NOTE_ON) && (ev->d2 != 0))
|
if(((ev->status & 0xF0) == MIDI_NOTE_ON) && (ev->d2 == 0)) /* Release by vol=0 */
|
||||||
{
|
{
|
||||||
pressNote(ev->status & 0x0F, ev->d1, ev->d2);
|
releaseNote(ev->status & 0x0F, ev->d1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(((ev->status & 0xF0) == MIDI_NOTE_ON) && (ev->d2 == 0)) //Release by vol=0
|
|
||||||
{
|
|
||||||
releaseNote(ev->status & 0x0F, ev->d1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if((ev->status & 0xF0) == MIDI_NOTE_OFF)
|
if((ev->status & 0xF0) == MIDI_NOTE_OFF)
|
||||||
{
|
{
|
||||||
releaseNote(ev->status & 0x0F, ev->d1);
|
releaseNote(ev->status & 0x0F, ev->d1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((ev->status & 0xF0) == MIDI_PRGM)
|
if((ev->status & 0xF0) == MIDI_PRGM)
|
||||||
{
|
{
|
||||||
if((ev->status & 0x0F) == 9)
|
if((ev->status & 0x0F) == 9)
|
||||||
printf("\nNOT PATCHING: Someone tried patching Channel 9 onto something?");
|
printf("\nNOT PATCHING: Someone tried patching Channel 9 onto something?");
|
||||||
else
|
else
|
||||||
setPatch(ev->status & 0x0F, ev->d1);
|
setPatch(ev->status & 0x0F, ev->d1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -259,61 +246,60 @@ void sendEvent(struct Event * ev)
|
||||||
|
|
||||||
int tick(struct MIDIfile * mf)
|
int tick(struct MIDIfile * mf)
|
||||||
{
|
{
|
||||||
if(mf==NULL)
|
if(mf==NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int a=0;
|
int a=0;
|
||||||
int tracksAdv=0;
|
int tracksAdv=0;
|
||||||
for(a=0; a<mf->numTracks; a++)
|
for(a=0; a<mf->numTracks; a++)
|
||||||
{
|
{
|
||||||
struct Track * tr = mf->tracks[a];
|
struct Track * tr = mf->tracks[a];
|
||||||
|
|
||||||
if(tr == NULL)
|
if(tr == NULL)
|
||||||
printf("\nNULL TRACK: %d", a);
|
printf("\nNULL TRACK: %d", a);
|
||||||
|
|
||||||
|
|
||||||
//BIG DEBUG STATEMENT
|
//BIG DEBUG STATEMENT
|
||||||
//printf("\nTrack %2d, Event = %4d of %4d, Delta = %5d, Next = %4d", a, tr->pos, tr->numEvents, tr->delta, getEvent(tr, tr->pos)->delta);
|
//printf("\nTrack %2d, Event = %4d of %4d, Delta = %5d, Next = %4d", a, tr->pos, tr->numEvents, tr->delta, getEvent(tr, tr->pos)->delta);
|
||||||
|
|
||||||
|
|
||||||
if(tr != NULL && (tr->pos < tr->numEvents))
|
if(tr != NULL && (tr->pos < tr->numEvents))
|
||||||
{
|
{
|
||||||
tr->delta++;
|
tr->delta++;
|
||||||
tracksAdv++;
|
tracksAdv++;
|
||||||
while(getEvent(tr, tr->pos)->delta <= tr->delta)
|
while(getEvent(tr, tr->pos)->delta <= tr->delta)
|
||||||
{
|
{
|
||||||
// printf("\nDelta = %d", tr->delta);
|
struct Event * e = getEvent(tr, tr->pos);
|
||||||
struct Event * e = getEvent(tr, tr->pos);
|
|
||||||
|
|
||||||
if(e->status != 0xFF)
|
if(e->status != 0xFF)
|
||||||
{
|
{
|
||||||
sendEvent(e);
|
sendEvent(e);
|
||||||
if(((e->status&0xF0) == MIDI_PRGM))
|
if(((e->status&0xF0) == MIDI_PRGM))
|
||||||
{
|
{
|
||||||
printf("\nPatch Event, patch[%d] ==> %d", e->status&0xF, e->d1);
|
printf("\nPatch Event, patch[%d] ==> %d", e->status&0xF, e->d1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(e->d1 == 0x51)
|
if(e->d1 == 0x51)
|
||||||
{
|
{
|
||||||
tempo = (((short)e->evData[0])<<16)|(((short)e->evData[1])<<8)|(e->evData[2]);
|
tempo = (((short)e->evData[0])<<16)|(((short)e->evData[1])<<8)|(e->evData[2]);
|
||||||
printf("\nMeta-Event: Tempo Set = %d", tempo);
|
printf("\nMeta-Event: Tempo Set = %d", tempo);
|
||||||
bpm=mf->div*1000000/tempo;
|
bpm=mf->div*1000000/tempo;
|
||||||
numberOfSamples=SAMPLE_RATE/bpm;
|
numberOfSamples=SAMPLE_RATE/bpm;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tr->delta = 0;
|
tr->delta = 0;
|
||||||
tr->pos++;
|
tr->pos++;
|
||||||
if(tr->pos>=(tr->numEvents-1))
|
if(tr->pos>=(tr->numEvents-1))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tracksAdv != 0)
|
if(tracksAdv != 0)
|
||||||
return 1;
|
return 1;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,158 +20,164 @@ extern struct plugin_api * rb;
|
||||||
|
|
||||||
struct Event * getEvent(struct Track * tr, int evNum)
|
struct Event * getEvent(struct Track * tr, int evNum)
|
||||||
{
|
{
|
||||||
return tr->dataBlock + (evNum*sizeof(struct Event));
|
return tr->dataBlock + (evNum*sizeof(struct Event));
|
||||||
}
|
}
|
||||||
|
|
||||||
void readTextBlock(int file, char * buf)
|
void readTextBlock(int file, char * buf)
|
||||||
{
|
{
|
||||||
char c = 0;
|
char c = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
c = readChar(file);
|
c = readChar(file);
|
||||||
} while(c == '\n' || c == ' ' || c=='\t');
|
} while(c == '\n' || c == ' ' || c=='\t');
|
||||||
|
|
||||||
rb->lseek(file, -1, SEEK_CUR);
|
rb->lseek(file, -1, SEEK_CUR);
|
||||||
int cp = 0;
|
int cp = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
c = readChar(file);
|
c = readChar(file);
|
||||||
buf[cp] = c;
|
buf[cp] = c;
|
||||||
cp++;
|
cp++;
|
||||||
} while (c != '\n' && c != ' ' && c != '\t' && !eof(file));
|
} while (c != '\n' && c != ' ' && c != '\t' && !eof(file));
|
||||||
buf[cp-1]=0;
|
buf[cp-1]=0;
|
||||||
rb->lseek(file, -1, SEEK_CUR);
|
rb->lseek(file, -1, SEEK_CUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Filename is the name of the config file
|
/* Filename is the name of the config file */
|
||||||
//The MIDI file should have been loaded at this point
|
/* The MIDI file should have been loaded at this point */
|
||||||
int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
|
int initSynth(struct MIDIfile * mf, char * filename, char * drumConfig)
|
||||||
{
|
{
|
||||||
char patchUsed[128];
|
char patchUsed[128];
|
||||||
char drumUsed[128];
|
char drumUsed[128];
|
||||||
int a=0;
|
int a=0;
|
||||||
for(a=0; a<MAX_VOICES; a++)
|
for(a=0; a<MAX_VOICES; a++)
|
||||||
{
|
{
|
||||||
voices[a].cp=0;
|
voices[a].cp=0;
|
||||||
voices[a].vol=0;
|
voices[a].vol=0;
|
||||||
voices[a].ch=0;
|
voices[a].ch=0;
|
||||||
voices[a].isUsed=0;
|
voices[a].isUsed=0;
|
||||||
voices[a].note=0;
|
voices[a].note=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(a=0; a<16; a++)
|
for(a=0; a<16; a++)
|
||||||
{
|
{
|
||||||
chVol[a]=100; //Default, not quite full blast..
|
chVol[a]=100; /* Default, not quite full blast.. */
|
||||||
chPanLeft[a]=64; //Center
|
chPanLeft[a]=64; /* Center */
|
||||||
chPanRight[a]=64; //Center
|
chPanRight[a]=64; /* Center */
|
||||||
chPat[a]=0; //Ac Gr Piano
|
chPat[a]=0; /* Ac Gr Piano */
|
||||||
chPW[a]=64; // .. not .. bent ?
|
chPW[a]=64; /* .. not .. bent ? */
|
||||||
}
|
}
|
||||||
for(a=0; a<128; a++)
|
for(a=0; a<128; a++)
|
||||||
{
|
{
|
||||||
patchSet[a]=NULL;
|
patchSet[a]=NULL;
|
||||||
drumSet[a]=NULL;
|
drumSet[a]=NULL;
|
||||||
patchUsed[a]=0;
|
patchUsed[a]=0;
|
||||||
drumUsed[a]=0;
|
drumUsed[a]=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Always load the piano.
|
/*
|
||||||
//Some files will assume its loaded without specifically
|
* Always load the piano.
|
||||||
//issuing a Patch command... then we wonder why we can't hear anything
|
* Some files will assume its loaded without specifically
|
||||||
patchUsed[0]=1;
|
* issuing a Patch command... then we wonder why we can't hear anything
|
||||||
|
*/
|
||||||
|
patchUsed[0]=1;
|
||||||
|
|
||||||
//Scan the file to see what needs to be loaded
|
/* Scan the file to see what needs to be loaded */
|
||||||
for(a=0; a<mf->numTracks; a++)
|
for(a=0; a<mf->numTracks; a++)
|
||||||
{
|
{
|
||||||
int ts=0;
|
unsigned int ts=0;
|
||||||
|
|
||||||
if(mf->tracks[a] == NULL)
|
if(mf->tracks[a] == NULL)
|
||||||
{
|
{
|
||||||
printf("\nNULL TRACK !!!");
|
printf("\nNULL TRACK !!!");
|
||||||
rb->splash(HZ*2, true, "Null Track in loader.");
|
rb->splash(HZ*2, true, "Null Track in loader.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(ts=0; ts<mf->tracks[a]->numEvents; ts++)
|
for(ts=0; ts<mf->tracks[a]->numEvents; ts++)
|
||||||
{
|
{
|
||||||
|
|
||||||
if((getEvent(mf->tracks[a], ts)->status) == (MIDI_NOTE_ON+9))
|
if((getEvent(mf->tracks[a], ts)->status) == (MIDI_NOTE_ON+9))
|
||||||
drumUsed[getEvent(mf->tracks[a], ts)->d1]=1;
|
drumUsed[getEvent(mf->tracks[a], ts)->d1]=1;
|
||||||
|
|
||||||
if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM)
|
if( (getEvent(mf->tracks[a], ts)->status & 0xF0) == MIDI_PRGM)
|
||||||
{
|
{
|
||||||
if(patchUsed[getEvent(mf->tracks[a], ts)->d1]==0)
|
if(patchUsed[getEvent(mf->tracks[a], ts)->d1]==0)
|
||||||
printf("\nI need to load patch %d.", getEvent(mf->tracks[a], ts)->d1);
|
printf("\nI need to load patch %d.", getEvent(mf->tracks[a], ts)->d1);
|
||||||
patchUsed[getEvent(mf->tracks[a], ts)->d1]=1;
|
patchUsed[getEvent(mf->tracks[a], ts)->d1]=1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int file = rb->open(filename, O_RDONLY);
|
int file = rb->open(filename, O_RDONLY);
|
||||||
if(file == -1)
|
if(file == -1)
|
||||||
{
|
{
|
||||||
rb->splash(HZ*2, true, "Bad patch config.\nDid you install the patchset?");
|
rb->splash(HZ*2, true, "Bad patch config.\nDid you install the patchset?");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char name[40];
|
char name[40];
|
||||||
char fn[40];
|
char fn[40];
|
||||||
|
|
||||||
//Scan our config file and load the right patches as needed
|
/* Scan our config file and load the right patches as needed */
|
||||||
int c = 0;
|
int c = 0;
|
||||||
rb->snprintf(name, 40, "");
|
rb->snprintf(name, 40, "");
|
||||||
for(a=0; a<128; a++)
|
for(a=0; a<128; a++)
|
||||||
{
|
{
|
||||||
while(readChar(file)!=' ' && !eof(file));
|
while(readChar(file)!=' ' && !eof(file));
|
||||||
readTextBlock(file, name);
|
readTextBlock(file, name);
|
||||||
|
|
||||||
rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name);
|
rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name);
|
||||||
printf("\nLOADING: <%s> ", fn);
|
printf("\nLOADING: <%s> ", fn);
|
||||||
|
|
||||||
if(patchUsed[a]==1)
|
if(patchUsed[a]==1)
|
||||||
patchSet[a]=gusload(fn);
|
{
|
||||||
|
patchSet[a]=gusload(fn);
|
||||||
|
|
||||||
// if(patchSet[a] == NULL)
|
if(patchSet[a] == NULL) /* There was an error loading it */
|
||||||
// return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while((c != '\n'))
|
while((c != '\n'))
|
||||||
c = readChar(file);
|
c = readChar(file);
|
||||||
}
|
}
|
||||||
rb->close(file);
|
rb->close(file);
|
||||||
|
|
||||||
file = rb->open(drumConfig, O_RDONLY);
|
file = rb->open(drumConfig, O_RDONLY);
|
||||||
if(file == -1)
|
if(file == -1)
|
||||||
{
|
{
|
||||||
rb->splash(HZ*2, true, "Bad drum config.\nDid you install the patchset?");
|
rb->splash(HZ*2, true, "Bad drum config.\nDid you install the patchset?");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Scan our config file and load the drum data
|
/* Scan our config file and load the drum data */
|
||||||
int idx=0;
|
int idx=0;
|
||||||
char number[30];
|
char number[30];
|
||||||
while(!eof(file))
|
while(!eof(file))
|
||||||
{
|
{
|
||||||
readTextBlock(file, number);
|
readTextBlock(file, number);
|
||||||
readTextBlock(file, name);
|
readTextBlock(file, name);
|
||||||
rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name);
|
rb->snprintf(fn, 40, "/.rockbox/patchset/%s.pat", name);
|
||||||
|
|
||||||
idx = rb->atoi(number);
|
idx = rb->atoi(number);
|
||||||
if(idx == 0)
|
if(idx == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(drumUsed[idx]==1)
|
if(drumUsed[idx]==1)
|
||||||
drumSet[idx]=gusload(fn);
|
{
|
||||||
|
drumSet[idx]=gusload(fn);
|
||||||
|
|
||||||
// if(drumSet[idx] == NULL)
|
if(drumSet[idx] == NULL) /* Error loading patch */
|
||||||
// return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while((c != '\n') && (c != 255) && (!eof(file)))
|
while((c != '\n') && (c != 255) && (!eof(file)))
|
||||||
c = readChar(file);
|
c = readChar(file);
|
||||||
}
|
}
|
||||||
rb->close(file);
|
rb->close(file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,7 +188,7 @@ struct GWaveform * wf IDATA_ATTR;
|
||||||
int s IDATA_ATTR;
|
int s IDATA_ATTR;
|
||||||
short s1 IDATA_ATTR;
|
short s1 IDATA_ATTR;
|
||||||
short s2 IDATA_ATTR;
|
short s2 IDATA_ATTR;
|
||||||
short sample IDATA_ATTR; //For synthSample
|
short sample IDATA_ATTR; /* For synthSample */
|
||||||
unsigned int cpShifted IDATA_ATTR;
|
unsigned int cpShifted IDATA_ATTR;
|
||||||
|
|
||||||
unsigned char b1 IDATA_ATTR;
|
unsigned char b1 IDATA_ATTR;
|
||||||
|
@ -191,31 +197,9 @@ unsigned char b2 IDATA_ATTR;
|
||||||
|
|
||||||
inline int getSample(int s)
|
inline int getSample(int s)
|
||||||
{
|
{
|
||||||
|
/* Sign conversion moved to guspat.c */
|
||||||
//16 bit samples
|
/* 8bit conversion NOT YET IMPLEMENTED in guspat.c */
|
||||||
if(wf->mode&1)
|
return ((short *) wf->data)[s];
|
||||||
{
|
|
||||||
|
|
||||||
if(s<<1 >= wf->wavSize)
|
|
||||||
{
|
|
||||||
printf("\n!!!!! %d \t %d", s<<1, wf->wavSize);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// signed short a = ((short *)wf->data)[s];
|
|
||||||
|
|
||||||
//Sign conversion moved into guspat.c
|
|
||||||
b1=wf->data[s<<1]+((wf->mode & 2) << 6);
|
|
||||||
b2=wf->data[(s<<1)|1]+((wf->mode & 2) << 6);
|
|
||||||
return (b1 | (b2<<8)) ;
|
|
||||||
|
|
||||||
//Get rid of this sometime
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ //8-bit samples
|
|
||||||
//Do we even have anything 8-bit in our set?
|
|
||||||
int b1=wf->data[s]+((wf->mode & 2) << 6);
|
|
||||||
return b1<<8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -223,190 +207,194 @@ inline int getSample(int s)
|
||||||
|
|
||||||
inline void setPoint(struct SynthObject * so, int pt)
|
inline void setPoint(struct SynthObject * so, int pt)
|
||||||
{
|
{
|
||||||
if(so->ch==9) //Drums, no ADSR
|
if(so->ch==9) /* Drums, no ADSR */
|
||||||
{
|
{
|
||||||
so->curOffset = 1<<27;
|
so->curOffset = 1<<27;
|
||||||
so->curRate = 1;
|
so->curRate = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(so->wf==NULL)
|
if(so->wf==NULL)
|
||||||
{
|
{
|
||||||
printf("\nCrap... null waveform...");
|
printf("\nCrap... null waveform...");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(so->wf->envRate==NULL)
|
if(so->wf->envRate==NULL)
|
||||||
{
|
{
|
||||||
printf("\nWaveform has no envelope set");
|
printf("\nWaveform has no envelope set");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
so->curPoint = pt;
|
so->curPoint = pt;
|
||||||
|
|
||||||
int r=0;
|
int r=0;
|
||||||
int rate = so->wf->envRate[pt];
|
int rate = so->wf->envRate[pt];
|
||||||
|
|
||||||
r=3-((rate>>6) & 0x3); // Some blatant Timidity code for rate conversion...
|
r=3-((rate>>6) & 0x3); /* Some blatant Timidity code for rate conversion... */
|
||||||
r*=3;
|
r*=3;
|
||||||
r = (rate & 0x3f) << r;
|
r = (rate & 0x3f) << r;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Okay. This is the rate shift. Timidity defaults to 9, and sets
|
* Okay. This is the rate shift. Timidity defaults to 9, and sets
|
||||||
it to 10 if you use the fast decay option. Slow decay sounds better
|
* it to 10 if you use the fast decay option. Slow decay sounds better
|
||||||
on some files, except on some other files... you get chords that aren't
|
* on some files, except on some other files... you get chords that aren't
|
||||||
done decaying yet.. and they dont harmonize with the next chord and it
|
* done decaying yet.. and they dont harmonize with the next chord and it
|
||||||
sounds like utter crap. Yes, even Timitidy does that. So I'm going to
|
* sounds like utter crap. Yes, even Timitidy does that. So I'm going to
|
||||||
default this to 10, and maybe later have an option to set it to 9
|
* default this to 10, and maybe later have an option to set it to 9
|
||||||
for longer decays.
|
* for longer decays.
|
||||||
*/
|
*/
|
||||||
so->curRate = r<<10;
|
so->curRate = r<<10;
|
||||||
|
|
||||||
//Do this here because the patches assume a 44100 sampling rate
|
/*
|
||||||
//We've halved our sampling rate, ergo the ADSR code will be
|
* Do this here because the patches assume a 44100 sampling rate
|
||||||
//called half the time. Ergo, double the rate to keep stuff
|
* We've halved our sampling rate, ergo the ADSR code will be
|
||||||
//sounding right.
|
* called half the time. Ergo, double the rate to keep stuff
|
||||||
so->curRate = so->curRate << 1;
|
* sounding right.
|
||||||
|
*/
|
||||||
|
so->curRate = so->curRate << 1;
|
||||||
|
|
||||||
|
|
||||||
so->targetOffset = so->wf->envOffset[pt]<<(20);
|
so->targetOffset = so->wf->envOffset[pt]<<(20);
|
||||||
if(pt==0)
|
if(pt==0)
|
||||||
so->curOffset = 0;
|
so->curOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void stopVoice(struct SynthObject * so)
|
inline void stopVoice(struct SynthObject * so)
|
||||||
{
|
{
|
||||||
if(so->state == STATE_RAMPDOWN)
|
if(so->state == STATE_RAMPDOWN)
|
||||||
return;
|
return;
|
||||||
so->state = STATE_RAMPDOWN;
|
so->state = STATE_RAMPDOWN;
|
||||||
so->decay = 255;
|
so->decay = 255;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline signed short int synthVoice()
|
inline signed short int synthVoice()
|
||||||
{
|
{
|
||||||
so = &voices[currentVoice];
|
so = &voices[currentVoice];
|
||||||
wf = so->wf;
|
wf = so->wf;
|
||||||
|
|
||||||
|
|
||||||
if(so->state != STATE_RAMPDOWN)
|
if(so->state != STATE_RAMPDOWN)
|
||||||
{
|
{
|
||||||
so->cp += so->delta;
|
so->cp += so->delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpShifted = so->cp >> 10;
|
cpShifted = so->cp >> 10;
|
||||||
|
|
||||||
if( (cpShifted >= (wf->wavSize>>1)) && (so->state != STATE_RAMPDOWN))
|
if( (cpShifted > (wf->numSamples) && (so->state != STATE_RAMPDOWN)))
|
||||||
stopVoice(so);
|
{
|
||||||
|
stopVoice(so);
|
||||||
|
}
|
||||||
|
|
||||||
s2 = getSample((cpShifted)+1);
|
s2 = getSample((cpShifted)+1);
|
||||||
|
|
||||||
if((wf->mode & (LOOP_REVERSE|LOOP_PINGPONG)) && so->loopState == STATE_LOOPING && (cpShifted <= (wf->startLoop>>1)))
|
/* LOOP_REVERSE|LOOP_PINGPONG = 24 */
|
||||||
{
|
if((wf->mode & (24)) && so->loopState == STATE_LOOPING && (cpShifted <= (wf->startLoop)))
|
||||||
if(wf->mode & LOOP_REVERSE)
|
{
|
||||||
{
|
if(wf->mode & LOOP_REVERSE)
|
||||||
so->cp = (wf->endLoop)<<9;
|
{
|
||||||
cpShifted = so->cp >> 10;
|
so->cp = (wf->endLoop)<<10;
|
||||||
s2=getSample((cpShifted));
|
cpShifted = wf->endLoop;
|
||||||
} else
|
s2=getSample((cpShifted));
|
||||||
{
|
} else
|
||||||
so->delta = -so->delta;
|
{
|
||||||
so->loopDir = LOOPDIR_FORWARD;
|
so->delta = -so->delta;
|
||||||
}
|
so->loopDir = LOOPDIR_FORWARD;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if((wf->mode & 28) && (so->cp>>10 >= wf->endLoop>>1))
|
if((wf->mode & 28) && (cpShifted >= wf->endLoop))
|
||||||
{
|
{
|
||||||
so->loopState = STATE_LOOPING;
|
so->loopState = STATE_LOOPING;
|
||||||
if((wf->mode & (24)) == 0)
|
if((wf->mode & (24)) == 0)
|
||||||
{
|
{
|
||||||
so->cp = (wf->startLoop)<<9;
|
so->cp = (wf->startLoop)<<10;
|
||||||
cpShifted = so->cp >> 10;
|
cpShifted = wf->startLoop;
|
||||||
s2=getSample((cpShifted));
|
s2=getSample((cpShifted));
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
so->delta = -so->delta;
|
so->delta = -so->delta;
|
||||||
so->loopDir = LOOPDIR_REVERSE;
|
so->loopDir = LOOPDIR_REVERSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Better, working, linear interpolation
|
/* Better, working, linear interpolation */
|
||||||
s1=getSample((cpShifted));
|
s1=getSample((cpShifted));
|
||||||
s = s1 + ((signed)((s2 - s1) * (so->cp & 1023))>>10);
|
s = s1 + ((signed)((s2 - s1) * (so->cp & 1023))>>10);
|
||||||
|
|
||||||
|
|
||||||
//ADSR COMMENT WOULD GO FROM HERE.........
|
/* ADSR COMMENT WOULD GO FROM HERE.........*/
|
||||||
|
|
||||||
if(so->curRate == 0)
|
if(so->curRate == 0)
|
||||||
stopVoice(so);
|
stopVoice(so);
|
||||||
|
|
||||||
|
|
||||||
if(so->ch != 9) //Stupid ADSR code... and don't do ADSR for drums
|
if(so->ch != 9) /* Stupid ADSR code... and don't do ADSR for drums */
|
||||||
{
|
{
|
||||||
if(so->curOffset < so->targetOffset)
|
if(so->curOffset < so->targetOffset)
|
||||||
{
|
{
|
||||||
so->curOffset += (so->curRate);
|
so->curOffset += (so->curRate);
|
||||||
if(so -> curOffset > so->targetOffset && so->curPoint != 2)
|
if(so -> curOffset > so->targetOffset && so->curPoint != 2)
|
||||||
{
|
{
|
||||||
if(so->curPoint != 5)
|
if(so->curPoint != 5)
|
||||||
setPoint(so, so->curPoint+1);
|
setPoint(so, so->curPoint+1);
|
||||||
else
|
else
|
||||||
stopVoice(so);
|
stopVoice(so);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
so->curOffset -= (so->curRate);
|
so->curOffset -= (so->curRate);
|
||||||
if(so -> curOffset < so->targetOffset && so->curPoint != 2)
|
if(so -> curOffset < so->targetOffset && so->curPoint != 2)
|
||||||
{
|
{
|
||||||
|
|
||||||
if(so->curPoint != 5)
|
if(so->curPoint != 5)
|
||||||
setPoint(so, so->curPoint+1);
|
setPoint(so, so->curPoint+1);
|
||||||
else
|
else
|
||||||
stopVoice(so);
|
stopVoice(so);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(so->curOffset < 0)
|
if(so->curOffset < 0)
|
||||||
so->isUsed=0; //This is OK
|
so->isUsed=0; /* This is OK because offset faded it out already */
|
||||||
|
|
||||||
|
|
||||||
s = (s * (so->curOffset >> 22) >> 6);
|
s = (s * (so->curOffset >> 22) >> 8);
|
||||||
|
|
||||||
// ............. TO HERE
|
/* ............. TO HERE */
|
||||||
|
|
||||||
|
|
||||||
if(so->state == STATE_RAMPDOWN)
|
if(so->state == STATE_RAMPDOWN)
|
||||||
{
|
{
|
||||||
so->decay--;
|
so->decay--;
|
||||||
if(so->decay == 0)
|
if(so->decay == 0)
|
||||||
so->isUsed=0;
|
so->isUsed=0;
|
||||||
}
|
s = (s * so->decay) >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
s = s * so->decay; s = s >> 10;
|
return s*((signed short int)so->vol*(signed short int)chVol[so->ch])>>14;
|
||||||
|
|
||||||
return s*((signed short int)so->vol*(signed short int)chVol[so->ch])>>14;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void synthSample(int * mixL, int * mixR)
|
inline void synthSample(int * mixL, int * mixR)
|
||||||
{
|
{
|
||||||
// signed int leftMix=0, rightMix=0,
|
*mixL = 0;
|
||||||
*mixL = 0;
|
*mixR = 0;
|
||||||
*mixR = 0;
|
for(currentVoice=0; currentVoice<MAX_VOICES; currentVoice++)
|
||||||
for(currentVoice=0; currentVoice<MAX_VOICES; currentVoice++)
|
{
|
||||||
{
|
if(voices[currentVoice].isUsed==1)
|
||||||
if(voices[currentVoice].isUsed==1)
|
{
|
||||||
{
|
sample = synthVoice(currentVoice);
|
||||||
sample = synthVoice(currentVoice);
|
*mixL += (sample*chPanLeft[voices[currentVoice].ch])>>7;
|
||||||
*mixL += (sample*chPanLeft[voices[currentVoice].ch])>>7;
|
*mixR += (sample*chPanRight[voices[currentVoice].ch])>>7;
|
||||||
*mixR += (sample*chPanRight[voices[currentVoice].ch])>>7;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Automatic Gain Control, anyone?
|
/* TODO: Automatic Gain Control, anyone? */
|
||||||
//Or, should this be implemented on the DSP's output volume instead?
|
/* Or, should this be implemented on the DSP's output volume instead? */
|
||||||
return; //No more ghetto lowpass filter.. linear intrpolation works well.
|
|
||||||
|
return; /* No more ghetto lowpass filter.. linear intrpolation works well. */
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,21 +20,22 @@
|
||||||
#define MAX_VOICES 100
|
#define MAX_VOICES 100
|
||||||
|
|
||||||
|
|
||||||
//Only define LOCAL_DSP on Simulator or else we're asking for trouble
|
/* Only define LOCAL_DSP on Simulator or else we're asking for trouble */
|
||||||
#if defined(SIMULATOR)
|
#if defined(SIMULATOR)
|
||||||
//Enable this to write to the soundcard via a /dsv/dsp symlink in /
|
/*Enable this to write to the soundcard via a /dsv/dsp symlink in */
|
||||||
// #define LOCAL_DSP
|
// #define LOCAL_DSP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(LOCAL_DSP)
|
#if defined(LOCAL_DSP)
|
||||||
// This is for writing to the DSP directly from the Simulator
|
/* This is for writing to the DSP directly from the Simulator */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <linux/soundcard.h>
|
#include <linux/soundcard.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "../../firmware/export/system.h"
|
||||||
|
|
||||||
#include "../../plugin.h"
|
#include "../../plugin.h"
|
||||||
|
|
||||||
|
@ -53,9 +54,9 @@ long bpm;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int fd=-1; //File descriptor where the output is written
|
int fd=-1; /* File descriptor where the output is written */
|
||||||
|
|
||||||
extern long tempo; //The sequencer keeps track of this
|
extern long tempo; /* The sequencer keeps track of this */
|
||||||
|
|
||||||
|
|
||||||
struct plugin_api * rb;
|
struct plugin_api * rb;
|
||||||
|
@ -66,27 +67,28 @@ struct plugin_api * rb;
|
||||||
|
|
||||||
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
|
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
|
||||||
{
|
{
|
||||||
TEST_PLUGIN_API(api);
|
TEST_PLUGIN_API(api);
|
||||||
rb = api;
|
rb = api;
|
||||||
TEST_PLUGIN_API(api);
|
TEST_PLUGIN_API(api);
|
||||||
(void)parameter;
|
(void)parameter;
|
||||||
rb = api;
|
rb = api;
|
||||||
|
|
||||||
if(parameter == NULL)
|
if(parameter == NULL)
|
||||||
{
|
{
|
||||||
rb->splash(HZ*2, true, " Play .MID file ");
|
rb->splash(HZ*2, true, " Play .MID file ");
|
||||||
return PLUGIN_OK;
|
return PLUGIN_OK;
|
||||||
}
|
}
|
||||||
rb->splash(HZ, true, parameter);
|
|
||||||
if(midimain(parameter) == -1)
|
rb->splash(HZ, true, parameter);
|
||||||
{
|
if(midimain(parameter) == -1)
|
||||||
return PLUGIN_ERROR;
|
{
|
||||||
}
|
return PLUGIN_ERROR;
|
||||||
rb->splash(HZ*3, true, "FINISHED PLAYING");
|
}
|
||||||
return PLUGIN_OK;
|
rb->splash(HZ*3, true, "FINISHED PLAYING");
|
||||||
|
return PLUGIN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
signed char outputBuffer[3000] IDATA_ATTR; //signed char.. gonna run out of iram ... !
|
signed char outputBuffer[3000] IDATA_ATTR; /* signed char.. gonna run out of iram ... ! */
|
||||||
|
|
||||||
|
|
||||||
int currentSample IDATA_ATTR;
|
int currentSample IDATA_ATTR;
|
||||||
|
@ -98,132 +100,133 @@ int outputSampleTwo IDATA_ATTR;
|
||||||
int midimain(void * filename)
|
int midimain(void * filename)
|
||||||
{
|
{
|
||||||
|
|
||||||
printf("\nHello.\n");
|
printf("\nHello.\n");
|
||||||
|
|
||||||
rb->splash(HZ/5, true, "LOADING MIDI");
|
rb->splash(HZ/5, true, "LOADING MIDI");
|
||||||
|
|
||||||
struct MIDIfile * mf = loadFile(filename);
|
struct MIDIfile * mf = loadFile(filename);
|
||||||
|
|
||||||
rb->splash(HZ/5, true, "LOADING PATCHES");
|
rb->splash(HZ/5, true, "LOADING PATCHES");
|
||||||
if (initSynth(mf, "/.rockbox/patchset/patchset.cfg", "/.rockbox/patchset/drums.cfg") == -1)
|
if (initSynth(mf, "/.rockbox/patchset/patchset.cfg", "/.rockbox/patchset/drums.cfg") == -1)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//This lets you hear the music through the sound card if you are on Simulator
|
/*
|
||||||
//Make a symlink, archos/dsp.raw and make it point to /dev/dsp or whatever
|
* This lets you hear the music through the sound card if you are on Simulator
|
||||||
//your sound device is.
|
* Make a symlink, archos/dsp.raw and make it point to /dev/dsp or whatever
|
||||||
|
* your sound device is.
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined(LOCAL_DSP)
|
#if defined(LOCAL_DSP)
|
||||||
fd=rb->open("/dsp.raw", O_WRONLY);
|
fd=rb->open("/dsp.raw", O_WRONLY);
|
||||||
int arg, status;
|
int arg, status;
|
||||||
int bit, samp, ch;
|
int bit, samp, ch;
|
||||||
|
|
||||||
arg = 16; // sample size
|
arg = 16; /* sample size */
|
||||||
status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
|
status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
|
||||||
status = ioctl(fd, SOUND_PCM_READ_BITS, &arg);
|
status = ioctl(fd, SOUND_PCM_READ_BITS, &arg);
|
||||||
bit=arg;
|
bit=arg;
|
||||||
|
|
||||||
|
|
||||||
arg = 2; //Number of channels, 1=mono
|
arg = 2; /* Number of channels, 1=mono */
|
||||||
status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
|
status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
|
||||||
status = ioctl(fd, SOUND_PCM_READ_CHANNELS, &arg);
|
status = ioctl(fd, SOUND_PCM_READ_CHANNELS, &arg);
|
||||||
ch=arg;
|
ch=arg;
|
||||||
|
|
||||||
arg = SAMPLE_RATE; //Yeah. sampling rate
|
arg = SAMPLE_RATE; /* Yeah. sampling rate */
|
||||||
status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
|
status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
|
||||||
status = ioctl(fd, SOUND_PCM_READ_RATE, &arg);
|
status = ioctl(fd, SOUND_PCM_READ_RATE, &arg);
|
||||||
samp=arg;
|
samp=arg;
|
||||||
#else
|
#else
|
||||||
file_info_struct file_info;
|
file_info_struct file_info;
|
||||||
file_info.samplerate = SAMPLE_RATE;
|
file_info.samplerate = SAMPLE_RATE;
|
||||||
file_info.infile = fd;
|
file_info.infile = fd;
|
||||||
file_info.channels = 2;
|
file_info.channels = 2;
|
||||||
file_info.bitspersample = 16;
|
file_info.bitspersample = 16;
|
||||||
local_init("/miditest.tmp", "/miditest.wav", &file_info, rb);
|
local_init("/miditest.tmp", "/miditest.wav", &file_info, rb);
|
||||||
fd = file_info.outfile;
|
fd = file_info.outfile;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
rb->splash(HZ/5, true, " Starting Playback ");
|
rb->splash(HZ/5, true, " I hope this works... ");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tick() will do one MIDI clock tick. Then, there's a loop here that
|
||||||
|
* will generate the right number of samples per MIDI tick. The whole
|
||||||
|
* MIDI playback is timed in terms of this value.. there are no forced
|
||||||
|
* delays or anything. It just produces enough samples for each tick, and
|
||||||
|
* the playback of these samples is what makes the timings right.
|
||||||
|
*
|
||||||
|
* This seems to work quite well.
|
||||||
|
*/
|
||||||
|
|
||||||
// tick() will do one MIDI clock tick. Then, there's a loop here that
|
printf("\nOkay, starting sequencing");
|
||||||
// will generate the right number of samples per MIDI tick. The whole
|
|
||||||
// MIDI playback is timed in terms of this value.. there are no forced
|
|
||||||
// delays or anything. It just produces enough samples for each tick, and
|
|
||||||
// the playback of these samples is what makes the timings right.
|
|
||||||
//
|
|
||||||
// This seems to work quite well.
|
|
||||||
|
|
||||||
|
|
||||||
printf("\nOkay, starting sequencing");
|
currentSample=0; /* Sample counting variable */
|
||||||
|
outputBufferPosition = 0;
|
||||||
|
|
||||||
|
|
||||||
currentSample=0; //Sample counting variable
|
bpm=mf->div*1000000/tempo;
|
||||||
outputBufferPosition = 0;
|
numberOfSamples=SAMPLE_RATE/bpm;
|
||||||
|
|
||||||
|
|
||||||
bpm=mf->div*1000000/tempo;
|
|
||||||
numberOfSamples=SAMPLE_RATE/bpm;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Tick() will return 0 if there are no more events left to play
|
/* Tick() will return 0 if there are no more events left to play */
|
||||||
while(tick(mf))
|
while(tick(mf))
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Tempo recalculation moved to sequencer.c to be done on a tempo event only
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
for(currentSample=0; currentSample<numberOfSamples; currentSample++)
|
||||||
|
{
|
||||||
|
|
||||||
//Some annoying math to compute the number of samples
|
synthSample(&outputSampleOne, &outputSampleTwo);
|
||||||
//to syntehsize per each MIDI tick.
|
|
||||||
|
|
||||||
//Yes we need to do this math each time because the tempo
|
|
||||||
//could have changed.
|
|
||||||
|
|
||||||
// On second thought, this can be moved to the event that
|
|
||||||
//recalculates the tempo, to save a little bit of CPU time.
|
|
||||||
for(currentSample=0; currentSample<numberOfSamples; currentSample++)
|
|
||||||
{
|
|
||||||
|
|
||||||
synthSample(&outputSampleOne, &outputSampleTwo);
|
|
||||||
|
|
||||||
|
|
||||||
//16-bit audio because, well, it's better
|
/*
|
||||||
// But really because ALSA's OSS emulation sounds extremely
|
* 16-bit audio because, well, it's better
|
||||||
//noisy and distorted when in 8-bit mode. I still do not know
|
* But really because ALSA's OSS emulation sounds extremely
|
||||||
//why this happens.
|
* noisy and distorted when in 8-bit mode. I still do not know
|
||||||
outputBuffer[outputBufferPosition]=outputSampleOne&0XFF; // Low byte first
|
* why this happens.
|
||||||
outputBufferPosition++;
|
*/
|
||||||
outputBuffer[outputBufferPosition]=outputSampleOne>>8; //High byte second
|
|
||||||
outputBufferPosition++;
|
|
||||||
|
|
||||||
outputBuffer[outputBufferPosition]=outputSampleTwo&0XFF; // Low byte first
|
outputBuffer[outputBufferPosition]=outputSampleOne&0XFF; // Low byte first
|
||||||
outputBufferPosition++;
|
outputBufferPosition++;
|
||||||
outputBuffer[outputBufferPosition]=outputSampleTwo>>8; //High byte second
|
outputBuffer[outputBufferPosition]=outputSampleOne>>8; //High byte second
|
||||||
outputBufferPosition++;
|
outputBufferPosition++;
|
||||||
|
|
||||||
|
outputBuffer[outputBufferPosition]=outputSampleTwo&0XFF; // Low byte first
|
||||||
|
outputBufferPosition++;
|
||||||
|
outputBuffer[outputBufferPosition]=outputSampleTwo>>8; //High byte second
|
||||||
|
outputBufferPosition++;
|
||||||
|
|
||||||
|
|
||||||
//As soon as we produce 2000 bytes of sound,
|
/*
|
||||||
//write it to the sound card. Why 2000? I have
|
* As soon as we produce 2000 bytes of sound,
|
||||||
//no idea. It's 1 AM and I am dead tired.
|
* write it to the sound card. Why 2000? I have
|
||||||
if(outputBufferPosition>=2000)
|
* no idea. It's 1 AM and I am dead tired.
|
||||||
{
|
*/
|
||||||
rb->write(fd, outputBuffer, 2000);
|
if(outputBufferPosition>=2000)
|
||||||
outputBufferPosition=0;
|
{
|
||||||
}
|
rb->write(fd, outputBuffer, 2000);
|
||||||
}
|
outputBufferPosition=0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// unloadFile(mf);
|
printf("\n");
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
#if !defined(LOCAL_DSP)
|
#if !defined(LOCAL_DSP)
|
||||||
|
|
||||||
close_wav(&file_info);
|
close_wav(&file_info);
|
||||||
#else
|
#else
|
||||||
rb->close(fd);
|
rb->close(fd);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue