You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
692 lines
16 KiB
692 lines
16 KiB
15 years ago
|
/**************************************************************************
|
||
|
|
||
|
gusout.cc - class GUSOut which implements support for Gravis
|
||
|
Ultrasound cards through a /dev/sequencer device
|
||
|
This file is part of LibKMid 0.9.5
|
||
|
Copyright (C) 1998,99,2000 Antonio Larrosa Jimenez
|
||
12 years ago
|
LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libtdemid.html
|
||
15 years ago
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU Library General Public
|
||
|
License as published by the Free Software Foundation; either
|
||
|
version 2 of the License, or (at your option) any later version.
|
||
|
|
||
|
This library is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
Library General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Library General Public License
|
||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
|
Boston, MA 02110-1301, USA.
|
||
|
|
||
|
Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org>
|
||
|
|
||
|
***************************************************************************/
|
||
|
#include "gusout.h"
|
||
|
#include "sndcard.h"
|
||
|
#include "midispec.h"
|
||
|
#include "gusvoices.h"
|
||
|
#include <sys/stat.h>
|
||
|
#include <unistd.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <stdio.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <errno.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/param.h>
|
||
|
#include <stdlib.h>
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include <config.h>
|
||
|
#endif
|
||
|
|
||
|
SEQ_USE_EXTBUF();
|
||
|
|
||
|
#ifdef HAVE_OSS_SUPPORT
|
||
|
struct pat_header
|
||
|
{
|
||
|
char magic[12];
|
||
|
char version[10];
|
||
|
char description[60];
|
||
|
unsigned char instruments;
|
||
|
char voices;
|
||
|
char channels;
|
||
|
unsigned short nr_waveforms;
|
||
|
unsigned short master_volume;
|
||
|
unsigned long data_size;
|
||
|
};
|
||
|
struct sample_header
|
||
|
{
|
||
|
char name[7];
|
||
|
unsigned char fractions;
|
||
|
long len;
|
||
|
long loop_start;
|
||
|
long loop_end;
|
||
|
unsigned short base_freq;
|
||
|
long low_note;
|
||
|
long high_note;
|
||
|
long base_note;
|
||
|
short detune;
|
||
|
unsigned char panning;
|
||
|
|
||
|
unsigned char envelope_rate[6];
|
||
|
unsigned char envelope_offset[6];
|
||
|
|
||
|
unsigned char tremolo_sweep;
|
||
|
unsigned char tremolo_rate;
|
||
|
unsigned char tremolo_depth;
|
||
|
|
||
|
unsigned char vibrato_sweep;
|
||
|
unsigned char vibrato_rate;
|
||
|
unsigned char vibrato_depth;
|
||
|
|
||
|
char modes;
|
||
|
|
||
|
short scale_frequency;
|
||
|
unsigned short scale_factor;
|
||
|
};
|
||
|
|
||
|
int get_dint(unsigned char *p)
|
||
|
{
|
||
|
unsigned int v=0;
|
||
|
|
||
|
for (int i=0;i<4;i++)
|
||
|
{
|
||
|
v |= (p[i] << (i*8));
|
||
|
}
|
||
|
return (int)v;
|
||
|
}
|
||
|
|
||
|
unsigned short get_word(unsigned char *p)
|
||
|
{
|
||
|
unsigned short v=0;
|
||
|
|
||
|
for (int i=0;i<2;i++)
|
||
|
v |= (*p++ << (i*8));
|
||
|
return (short)v;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
GUSOut::GUSOut(int d,int total)
|
||
|
{
|
||
|
seqfd = -1;
|
||
|
devicetype=KMID_GUS;
|
||
|
device= d;
|
||
|
_ok=1;
|
||
|
|
||
|
use8bit=0;
|
||
|
nvoices=total;
|
||
|
vm=new VoiceManager(nvoices);
|
||
|
}
|
||
|
|
||
|
GUSOut::~GUSOut()
|
||
|
{
|
||
|
closeDev();
|
||
|
|
||
|
delete vm;
|
||
|
if (delete_GUS_patches_directory)
|
||
|
{
|
||
|
free((char *)GUS_patches_directory);
|
||
|
delete_GUS_patches_directory = 0;
|
||
|
GUS_patches_directory="/etc";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
|
||
|
//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);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
void GUSOut::closeDev (void)
|
||
|
{
|
||
|
if (!ok()) return;
|
||
|
vm->clearLists();
|
||
|
//if (seqfd>=0)
|
||
|
// close(seqfd);
|
||
|
seqfd=-1;
|
||
|
}
|
||
|
|
||
|
void GUSOut::initDev (void)
|
||
|
{
|
||
|
#ifdef HAVE_OSS_SUPPORT
|
||
|
int chn;
|
||
|
if (!ok()) return;
|
||
|
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
|
||
|
}
|
||
|
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
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]);
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
void GUSOut::sysex(uchar *, ulong )
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
void GUSOut::setGUSPatchesDirectory(const char *dir)
|
||
|
{
|
||
|
if ((dir==NULL)||(dir[0]==0)) return;
|
||
|
if (delete_GUS_patches_directory)
|
||
|
free((char *)GUS_patches_directory);
|
||
|
|
||
|
GUS_patches_directory = strdup(dir);
|
||
|
delete_GUS_patches_directory=1;
|
||
|
}
|
||
|
|
||
|
const char *GUSOut::patchName(int pgm)
|
||
|
{
|
||
|
return GUS_voice_names[pgm];
|
||
|
}
|
||
|
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
int compare_decreasing(const void *a,const void *b)
|
||
|
{
|
||
|
struct instr_gm
|
||
|
{
|
||
|
int used;
|
||
|
int pgm;
|
||
|
};
|
||
|
instr_gm *ai=(instr_gm *)a;
|
||
|
instr_gm *bi=(instr_gm *)b;
|
||
|
return ai->used<bi->used;
|
||
|
}
|
||
|
|
||
|
|
||
|
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";
|
||
|
const char *GUSOut::GUS_patches_directory="/usr/share/ultrasnd";
|
||
|
|
||
|
int GUSOut::delete_GUS_patches_directory = 0;
|
||
|
/* No, this doesn't delete any file :-) it's just for internal use */
|