Source Code (Use browser search to find items of interest.)
Class Index
kdelibs'GUSOut (./kdelibs/libkmid/gusout.h:45)
class GUSOut : public MidiOut
{
private:
class GUSOutPrivate;
GUSOutPrivate *di;
int patchloaded[256];
int nvoices;
int use8bit; // Use 8 bit patches, instead of 16 bits to use less memory
VoiceManager *vm;
int totalmemory; // Total memory in soundcard
int freememory; // Free memory
void patchesLoadingOrder(int *patchesused,int *patchesordered);
char *patchName(int pgm);
public:
/**
* Constructor. See @ref MidiOut::MidiOut() for more information.
*/
GUSOut(int d=0,int total =12);
/**
* Destructor.
*/
~GUSOut();
/**
* See @ref MidiOut::openDev()
*/
virtual void openDev (int sqfd);
/**
* See @ref MidiOut::closeDev()
*/
virtual void closeDev (void);
/**
* See @ref MidiOut::initDev()
*/
virtual void initDev (void);
/**
* See @ref MidiOut::noteOn()
*/
virtual void noteOn ( uchar chn, uchar note, uchar vel );
/**
* See @ref MidiOut::noteOff()
*/
virtual void noteOff ( uchar chn, uchar note, uchar vel );
/**
* See @ref MidiOut::keyPressure()
*/
virtual void keyPressure ( uchar chn, uchar note, uchar vel );
/**
* See @ref MidiOut::chnPatchChange()
*/
virtual void chnPatchChange ( uchar chn, uchar patch );
/**
* See @ref MidiOut::chnPressure()
*/
virtual void chnPressure ( uchar chn, uchar vel );
/**
* See @ref MidiOut::chnPitchBender()
*/
virtual void chnPitchBender ( uchar chn, uchar lsb, uchar msb );
/**
* See @ref MidiOut::chnController()
*/
virtual void chnController ( uchar chn, uchar ctl , uchar v );
/**
* It's an empty function, as GUS synths don't support System Exclusive
* messages
*/
virtual void sysex ( uchar *data,ulong size);
/**
* See @ref DeviceManager::setPatchesToUse() . All the information about this
* member is explained there because it's (for now) just a simple call to this
* function when the device used is a GUS device, and you're supposed to use
* a DeviceManager object instead of a GUSOut object except in rare ocassions.
*
* @see #patch()
* @see #loadPatch()
*/
void setPatchesToUse(int *patchesused);
/**
* Loads a single patch on the synthesizer memory.
* @param pgm is the number of the GM patch when pgm is between 0 and 127.
* Values from 128 to 255 are used to represent the percussion instruments.
* @return 0 if OK and -1 if there was an error (patch not found, not enough
* memory, etc.)
*
* @see #patch()
* @see #setPatchesToUse()
*/
int loadPatch (int pgm);
/**
* Returns p if the patch with number p has been correctly loaded.
* In the case it hasn't been loaded, it returns the number of another patch
* that is loaded and that should be used instead.
*
* @see #loadPatch()
* @see #setPatchesToUse()
*/
int patch(int p);
private:
static const char *GUS_patches_directory;
static int delete_GUS_patches_directory;
public:
/**
* Sets the directory where the GUS patches are stored, that is, where the
* acpiano.pat, ... files can be found.
*
* It will store a copy of the parameter, so you should delete the memory
* used by the parameter you passed.
*/
static void setGUSPatchesDirectory(const char *dir);
};
kdelibs'GUSOut::GUSOut() (./kdelibs/libkmid/gusout.cc:112)
GUSOut::GUSOut(int d,int total)
{
seqfd = -1;
devicetype=KMID_GUS;
device= d;
#ifdef HANDLETIMEINDEVICES
count=0.0;
lastcount=0.0;
rate=100;
#endif
_ok=1;
use8bit=0;
nvoices=total;
vm=new VoiceManager(nvoices);
}
kdelibs'GUSOut::~GUSOut() (./kdelibs/libkmid/gusout.cc:129)
GUSOut::~GUSOut()
{
delete map;
closeDev();
if (delete_GUS_patches_directory)
{
delete GUS_patches_directory;
delete_GUS_patches_directory = 0;
GUS_patches_directory="/etc";
}
}
kdelibs'GUSOut::openDev() (./kdelibs/libkmid/gusout.cc:141)
void GUSOut::openDev (int sqfd)
{
_ok=1;
seqfd = sqfd;
//vm->clearLists();
if (seqfd==-1)
{
printfdebug("ERROR: Could not open /dev/sequencer\n");
return;
}
#ifdef HAVE_OSS_SUPPORT
#ifdef HANDLETIMEINDEVICES
ioctl(seqfd,SNDCTL_SEQ_NRSYNTHS,&ndevs);
ioctl(seqfd,SNDCTL_SEQ_NRMIDIS,&nmidiports);
rate=0;
int r=ioctl(seqfd,SNDCTL_SEQ_CTRLRATE,&rate);
if ((r==-1)||(rate<=0)) rate=HZ;
convertrate=1000/rate;
count=0.0;
lastcount=0.0;
#endif
//seqbuf_clean();
//ioctl(seqfd,SNDCTL_SEQ_RESET);
//ioctl(seqfd,SNDCTL_SEQ_PANIC);
if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &device)==-1)
{
printfdebug("Error reseting gus samples. Please report\n");
};
use8bit=0;
totalmemory = device;
ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &totalmemory);
freememory = device;
ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freememory);
printfdebug("GUS Device %d opened (%d voices)\n",device,nvoices);
#ifdef HANDLETIMEINDEVICES
printfdebug("Number of synth devices : %d\n",ndevs);
printfdebug("Number of midi ports : %d\n",nmidiports);
printfdebug("Rate : %d\n",rate);
#endif
#endif
}
kdelibs'GUSOut::closeDev() (./kdelibs/libkmid/gusout.cc:191)
void GUSOut::closeDev (void)
{
if (!ok()) return;
#ifdef HANDLETIMEINDEVICES
SEQ_STOP_TIMER();
SEQ_DUMPBUF();
#endif
vm->clearLists();
//if (seqfd>=0)
// close(seqfd);
seqfd=-1;
}
kdelibs'GUSOut::initDev() (./kdelibs/libkmid/gusout.cc:204)
void GUSOut::initDev (void)
{
#ifdef HAVE_OSS_SUPPORT
int chn;
if (!ok()) return;
#ifdef HANDLETIMEINDEVICES
count=0.0;
lastcount=0.0;
#endif
uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7};
sysex(gm_reset, sizeof(gm_reset));
for (chn=0;chn<16;chn++)
{
chnmute[chn]=0;
chnPatchChange(chn,0);
// chnPressure(chn,127);
chnPitchBender(chn, 0x00, 0x40);
chnController(chn, CTL_MAIN_VOLUME,127);
chnController(chn, CTL_EXT_EFF_DEPTH, 0);
chnController(chn, CTL_CHORUS_DEPTH, 0);
chnController(chn, 0x4a, 127);
}
for (int i = 0; i < nvoices; i++)
{
SEQ_CONTROL(device, i, SEQ_VOLMODE, VOL_METHOD_LINEAR);
SEQ_STOP_NOTE(device, i, vm->note(i), 64);
}
#endif
}
kdelibs'GUSOut::patch() (./kdelibs/libkmid/gusout.cc:238)
int GUSOut::patch(int p)
{
if (patchloaded[p]==1) return p;
printfdebug("Not loaded %d!\n",p);
p=0;
while ((p<256)&&(patchloaded[p]==0)) p++;
return p;
}
kdelibs'GUSOut::noteOn() (./kdelibs/libkmid/gusout.cc:247)
void GUSOut::noteOn (uchar chn, uchar note, uchar vel)
{
if (vel==0)
{
noteOff(chn,note,vel);
}
else
{
if (chn==PERCUSSION_CHANNEL)
{
if (patchloaded[note+128]==0) return;
else
if (patchloaded[chnpatch[chn]]==0) return;
};
int v=vm->allocateVoice(chn,note);
int p;
if (chn==PERCUSSION_CHANNEL)
SEQ_SET_PATCH(device,v ,p=patch(note+128))
else
SEQ_SET_PATCH(device,v ,p=map->patch(chn,chnpatch[chn]));
SEQ_BENDER(device, v, chnbender[chn]);
SEQ_START_NOTE(device, v, note, vel);
// SEQ_CONTROL(device, v, CTL_MAIN_VOLUME, chncontroller[chn][CTL_MAIN_VOLUME]);
SEQ_CHN_PRESSURE(device, v , chnpressure[chn]);
}
printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
}
kdelibs'GUSOut::noteOff() (./kdelibs/libkmid/gusout.cc:277)
void GUSOut::noteOff (uchar chn, uchar note, uchar vel)
{
int i;
vm->initSearch();
while ((i=vm->search(chn,note))!=-1)
{
SEQ_STOP_NOTE(device, i, note, vel);
vm->deallocateVoice(i);
}
#ifdef GUSOUTDEBUG
printf("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
#endif
}
kdelibs'GUSOut::keyPressure() (./kdelibs/libkmid/gusout.cc:292)
void GUSOut::keyPressure (uchar chn, uchar note, uchar vel)
{
int i;
vm->initSearch();
while ((i=vm->search(chn,note))!=-1)
SEQ_KEY_PRESSURE(device, i, note,vel);
}
kdelibs'GUSOut::chnPatchChange() (./kdelibs/libkmid/gusout.cc:300)
void GUSOut::chnPatchChange (uchar chn, uchar patch)
{
if (chn==PERCUSSION_CHANNEL) return;
int i;
vm->initSearch();
while ((i=vm->search(chn))!=-1)
SEQ_SET_PATCH(device,i,map->patch(chn,patch));
chnpatch[chn]=patch;
}
kdelibs'GUSOut::chnPressure() (./kdelibs/libkmid/gusout.cc:311)
void GUSOut::chnPressure (uchar chn, uchar vel)
{
/* int i;
vm->initSearch();
while ((i=vm->search(chn))!=-1)
SEQ_CHN_PRESSURE(device, i , vel);
chnpressure[chn]=vel;
*/
}
kdelibs'GUSOut::chnPitchBender() (./kdelibs/libkmid/gusout.cc:321)
void GUSOut::chnPitchBender(uchar chn,uchar lsb, uchar msb)
{
chnbender[chn]=((int)msb<<7) | (lsb & 0x7F);
int i;
vm->initSearch();
while ((i=vm->search(chn))!=-1)
SEQ_BENDER(device, i, chnbender[chn]);
}
kdelibs'GUSOut::chnController() (./kdelibs/libkmid/gusout.cc:331)
void GUSOut::chnController (uchar chn, uchar ctl, uchar v)
{
if ((ctl==11)||(ctl==7))
{
v=(v*volumepercentage)/100;
if (v>127) v=127;
};
int i;
vm->initSearch();
while ((i=vm->search(chn))!=-1)
SEQ_CONTROL(device, i, ctl, v);
chncontroller[chn][ctl]=v;
}
kdelibs'GUSOut::sysex() (./kdelibs/libkmid/gusout.cc:347)
void GUSOut::sysex(uchar *, ulong )
{
}
kdelibs'GUSOut::setGUSPatchesDirectory() (./kdelibs/libkmid/gusout.cc:352)
void GUSOut::setGUSPatchesDirectory(const char *dir)
{
if ((dir==NULL)||(dir[0]==0)) return;
if (delete_GUS_patches_directory) delete GUS_patches_directory;
char *GUS_patches_directory2=new char[strlen(dir)+1];
strcpy(GUS_patches_directory2,dir);
GUS_patches_directory = GUS_patches_directory2;
delete_GUS_patches_directory=1;
}
kdelibs'GUSOut::patchName() (./kdelibs/libkmid/gusout.cc:362)
char *GUSOut::patchName(int pgm)
{
return GUS_voice_names[pgm];
}
kdelibs'GUSOut::loadPatch() (./kdelibs/libkmid/gusout.cc:368)
int GUSOut::loadPatch(int pgm)
{
#ifdef HAVE_OSS_SUPPORT
struct pat_header header;
struct sample_header sample;
if (patchloaded[pgm]==1)
{
#ifdef GUSOUTDEBUG
printf("Trying to reload a patch. This should never happen, please report.\n");
#endif
return 0;
}
if ((patchName(pgm)==NULL)||((patchName(pgm))[0]==0))
{
#ifdef GUSOUTDEBUG
printf("Couldn't guess patch name for patch number %d\n",pgm);
#endif
return -1;
}
char *s=new char[strlen(GUS_patches_directory)+strlen(patchName(pgm))+10];
if (s==NULL) return -1;
sprintf(s,"%s/%s.pat",GUS_patches_directory,patchName(pgm));
#ifdef GUSOUTDEBUG
printf("Loading patch : %s\n",s);
#endif
struct patch_info *patch=NULL;
struct stat info;
if (stat(s, &info)==-1)
{
#ifdef GUSOUTDEBUG
printf("File %s doesn't exist\n",s);
#endif
return -1;
}
FILE *fh=fopen(s,"rb");
if (fh==NULL)
{
#ifdef GUSOUTDEBUG
printf("Couldn't open patch %s\n",s);
#endif
return -1;
}
unsigned char tmp[256];
if (fread(tmp,1,0xef,fh)!=0xef)
{
fclose(fh);
#ifdef GUSOUTDEBUG
printf("Short file ! \n");
#endif
return -1;
}
memcpy ((char *) &header, tmp, sizeof (header));
if (strncmp(header.magic,"GF1PATCH110",12)!=0)
{
#ifdef GUSOUTDEBUG
printf("File %s is corrupted or it isn't a patch file\n",s);
#endif
return -1;
}
if (strncmp(header.version,"ID#000002",10)!=0)
{
#ifdef GUSOUTDEBUG
printf("File %s's version is not supported\n",s);
#endif
return -1;
}
unsigned short nWaves= *(unsigned short *)&tmp[85];
#ifdef GUSOUTDEBUG
unsigned short masterVolume= *(unsigned short *)&tmp[87];
printf("nWaves: %d\n",nWaves);
printf("masterVolume : %d\n",masterVolume);
#endif
unsigned short i;
int offset=0xef;
for (i=0;i<nWaves;i++)
{
fseek(fh,offset,SEEK_SET);
if (fread(tmp,1,sizeof(sample),fh) != sizeof(sample))
{
fclose(fh);
#ifdef GUSOUTDEBUG
printf("Short file\n");
#endif
return -1;
}
memcpy ((char *) &sample, tmp, sizeof (sample));
sample.fractions = (char)tmp[7];
sample.len = get_dint(&tmp[8]);
sample.loop_start = get_dint(&tmp[12]);
sample.loop_end = get_dint(&tmp[16]);
sample.base_freq = get_word(&tmp[20]);
sample.low_note = get_dint(&tmp[22]);
sample.high_note = get_dint(&tmp[26]);
sample.base_note = get_dint(&tmp[30]);
sample.detune = (short)get_word(&tmp[34]);
sample.panning = (unsigned char) tmp[36];
memcpy (sample.envelope_rate, &tmp[37], 6);
memcpy (sample.envelope_offset, &tmp[43], 6);
sample.tremolo_sweep = (unsigned char) tmp[49];
sample.tremolo_rate = (unsigned char) tmp[50];
sample.tremolo_depth = (unsigned char) tmp[51];
sample.vibrato_sweep = (unsigned char) tmp[52];
sample.vibrato_rate = (unsigned char) tmp[53];
sample.vibrato_depth = (unsigned char) tmp[54];
sample.modes = (unsigned char) tmp[55];
sample.scale_frequency = (short)get_word(&tmp[56]);
sample.scale_factor = get_word(&tmp[58]);
offset = offset + 96;
patch = (struct patch_info *) malloc(sizeof (*patch) + sample.len);
if (patch == NULL)
{
#ifdef GUSOUTDEBUG
printf("Not enough memory\n");
#endif
return -1;
}
patch->key = GUS_PATCH;
patch->device_no = device;
patch->instr_no = pgm;
patch->mode = sample.modes | WAVE_TREMOLO | WAVE_VIBRATO | WAVE_SCALE;
patch->len = sample.len;
patch->loop_start = sample.loop_start;
patch->loop_end = sample.loop_end;
patch->base_note = sample.base_note;
patch->high_note = sample.high_note;
patch->low_note = sample.low_note;
patch->base_freq = sample.base_freq;
patch->detuning = sample.detune;
patch->panning = (sample.panning - 7) * 16;
memcpy (patch->env_rate, sample.envelope_rate, 6);
memcpy (patch->env_offset, sample.envelope_offset, 6);
patch->tremolo_sweep = sample.tremolo_sweep;
patch->tremolo_rate = sample.tremolo_rate;
patch->tremolo_depth = sample.tremolo_depth;
patch->vibrato_sweep = sample.vibrato_sweep;
patch->vibrato_rate = sample.vibrato_rate;
patch->vibrato_depth = sample.vibrato_depth;
patch->scale_frequency = sample.scale_frequency;
patch->scale_factor = sample.scale_factor;
patch->volume = header.master_volume;
if (fseek (fh, offset, 0) == -1)
{
fclose(fh);
return -1;
}
if ((long)fread (patch->data, 1,sample.len,fh) != sample.len)
{
#ifdef GUSOUTDEBUG
printf ("Short file\n");
#endif
return -1;
}
SEQ_WRPATCH (patch, sizeof (*patch) + sample.len);
offset = offset + sample.len;
}
patchloaded[pgm]=1;
fclose(fh);
free(patch); // Shouldn't this 'free' be within the 'for' loop ?
delete s;
freememory = device;
ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freememory);
#endif
return 0;
}
kdelibs'GUSOut::setPatchesToUse() (./kdelibs/libkmid/gusout.cc:555)
void GUSOut::setPatchesToUse(int *patchesused)
{
#ifdef HAVE_OSS_SUPPORT
int k;
for (k=0;k<256;k++) patchloaded[k]=0;
int patchesordered[256]; //This holds the pgm used ordered by a method which
// put first the patches more oftenly used, and then the least
// In example, if a song only uses a piano and a splash cymbal,
// This is set to : 0,188,-1,-1,-1,-1 ...
patchesLoadingOrder(patchesused,patchesordered);
// If above line doesn't work, perhaps you could try this ? :
// for (int j=0;j<256;j++) patchesordered[j]=patchesused[j];
#ifdef GUSOUTDEBUG
printf("Patches used : \n");
for (k=0;k<256;k++)
{
if (patchesused[k]!=-1) printf("%d,",patchesused[k]);
}
printf("\n Patches used, sorted :\n");
for (k=0;k<256;k++)
{
if (patchesordered[k]!=-1) printf("%d,",patchesordered[k]);
}
#endif
int i=0;
while (patchesordered[i]!=-1)
{
#ifdef GUSOUTDEBUG
printf("Load Patch : %d\n",patchesordered[i]);
#endif
loadPatch(patchesordered[i]);
i++;
}
#endif
}
kdelibs'GUSOut::patchesLoadingOrder() (./kdelibs/libkmid/gusout.cc:607)
void GUSOut::patchesLoadingOrder(int *patchesused,int *patchesordered)
{
struct instr_gm
{
int used;
int pgm;
};
instr_gm tempmelody[128];
instr_gm tempdrums[128];
int i,j;
for (i=0,j=128;i<128;i++,j++)
{
tempmelody[i].used=patchesused[i];
tempmelody[i].pgm=i;
tempdrums[i].used=patchesused[j];
tempdrums[i].pgm=j;
}
/* SORT */ // Decreasing order (first most used patch, then less used patch)
qsort(&tempmelody[0],128,sizeof(instr_gm),compare_decreasing);
qsort(&tempdrums[0],128,sizeof(instr_gm),compare_decreasing);
/* Once they are sorted, the result is put on patchesordered in the following
* way : If tempmelody is : M0 M1 M2 M3 ... M127 and tempdrums is :
* D0 D1 D2 D3 ... D127, the result is :
* M0 D0 M1 M2 D1 M3 M4 D2 M5 M6 D3 ...
* P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 P10 ...
*/
#ifdef GUSOUTDEBUG
for (int k=0;k<128;k++)
{
printf("%d - %d\n",tempmelody[k].used,tempmelody[k].pgm);
}
for (int k=0;k<128;k++)
{
printf("%d : %d\n",tempdrums[k].used,tempdrums[k].pgm);
}
#endif
i=0;
int totalmelody=0;
while ((i<128)&&(tempmelody[i].used!=0))
{
totalmelody++;
i++;
}
i=0;
int totaldrums=0;
while ((i<128)&&(tempdrums[i].used!=0))
{
totaldrums++;
i++;
}
#ifdef GUSOUTDEBUG
printf("Totalmelody : %d,totaldrums : %d\n",totalmelody,totaldrums);
#endif
int tgt=0;
int tm=totalmelody;
int td=totaldrums;
int cm,cd;
cm=cd=0;
if ((tm!=0)&&(td!=0))
{
patchesordered[0]=tempmelody[0].pgm;
patchesordered[1]=tempdrums[0].pgm;
tm--;td--;
cm++;cd++;
tgt+=2;
while ((tm>0)&&(td>0))
{
if (((tgt-1)%3)==0)
{
patchesordered[tgt]=tempdrums[cd].pgm;
cd++;
td--;
}
else
{
patchesordered[tgt]=tempmelody[cm].pgm;
cm++;
tm--;
}
tgt++;
}
}
while (tm>0)
{
patchesordered[tgt]=tempmelody[cm].pgm;
tgt++;
cm++;
tm--;
}
while (td>0)
{
patchesordered[tgt]=tempdrums[cd].pgm;
tgt++;
cd++;
td--;
}
// Now we put as not used (-1) the rest of the array
while (tgt<256)
{
patchesordered[tgt]=-1;
tgt++;
}
}
//char *GUSOut::GUS_patches_directory="/mnt/dosc/gravis/patches";