diff options
Diffstat (limited to 'libkmid/gusout.cc')
-rw-r--r-- | libkmid/gusout.cc | 691 |
1 files changed, 0 insertions, 691 deletions
diff --git a/libkmid/gusout.cc b/libkmid/gusout.cc deleted file mode 100644 index 6b207956b..000000000 --- a/libkmid/gusout.cc +++ /dev/null @@ -1,691 +0,0 @@ -/************************************************************************** - - 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 - LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libkmid.html - - 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 */ |