00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "gusout.h"
00028 #include "sndcard.h"
00029 #include "midispec.h"
00030 #include "gusvoices.h"
00031 #include <sys/stat.h>
00032 #include <unistd.h>
00033 #include <fcntl.h>
00034 #include <stdio.h>
00035 #include <sys/ioctl.h>
00036 #include <errno.h>
00037 #include <string.h>
00038 #include <sys/param.h>
00039 #include <stdlib.h>
00040 #ifdef HAVE_CONFIG_H
00041 #include <config.h>
00042 #endif
00043
00044 SEQ_USE_EXTBUF();
00045
00046 #ifdef HAVE_OSS_SUPPORT
00047 struct pat_header
00048 {
00049 char magic[12];
00050 char version[10];
00051 char description[60];
00052 unsigned char instruments;
00053 char voices;
00054 char channels;
00055 unsigned short nr_waveforms;
00056 unsigned short master_volume;
00057 unsigned long data_size;
00058 };
00059 struct sample_header
00060 {
00061 char name[7];
00062 unsigned char fractions;
00063 long len;
00064 long loop_start;
00065 long loop_end;
00066 unsigned short base_freq;
00067 long low_note;
00068 long high_note;
00069 long base_note;
00070 short detune;
00071 unsigned char panning;
00072
00073 unsigned char envelope_rate[6];
00074 unsigned char envelope_offset[6];
00075
00076 unsigned char tremolo_sweep;
00077 unsigned char tremolo_rate;
00078 unsigned char tremolo_depth;
00079
00080 unsigned char vibrato_sweep;
00081 unsigned char vibrato_rate;
00082 unsigned char vibrato_depth;
00083
00084 char modes;
00085
00086 short scale_frequency;
00087 unsigned short scale_factor;
00088 };
00089
00090 int get_dint(unsigned char *p)
00091 {
00092 unsigned int v=0;
00093
00094 for (int i=0;i<4;i++)
00095 {
00096 v |= (p[i] << (i*8));
00097 }
00098 return (int)v;
00099 }
00100
00101 unsigned short get_word(unsigned char *p)
00102 {
00103 unsigned short v=0;
00104
00105 for (int i=0;i<2;i++)
00106 v |= (*p++ << (i*8));
00107 return (short)v;
00108 }
00109
00110 #endif
00111
00112 GUSOut::GUSOut(int d,int total)
00113 {
00114 seqfd = -1;
00115 devicetype=KMID_GUS;
00116 device= d;
00117 _ok=1;
00118
00119 use8bit=0;
00120 nvoices=total;
00121 vm=new VoiceManager(nvoices);
00122 }
00123
00124 GUSOut::~GUSOut()
00125 {
00126 closeDev();
00127
00128 delete vm;
00129 if (delete_GUS_patches_directory)
00130 {
00131 free((char *)GUS_patches_directory);
00132 delete_GUS_patches_directory = 0;
00133 GUS_patches_directory="/etc";
00134 }
00135 }
00136
00137 void GUSOut::openDev (int sqfd)
00138 {
00139 _ok=1;
00140 seqfd = sqfd;
00141
00142 if (seqfd==-1)
00143 {
00144 printfdebug("ERROR: Could not open /dev/sequencer\n");
00145 return;
00146 }
00147
00148 #ifdef HAVE_OSS_SUPPORT
00149
00150
00151
00152
00153
00154 if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &device)==-1)
00155 {
00156 printfdebug("Error reseting gus samples. Please report\n");
00157 };
00158 use8bit=0;
00159 totalmemory = device;
00160 ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &totalmemory);
00161 freememory = device;
00162 ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freememory);
00163
00164 #endif
00165
00166
00167 }
00168
00169 void GUSOut::closeDev (void)
00170 {
00171 if (!ok()) return;
00172 vm->clearLists();
00173
00174
00175 seqfd=-1;
00176 }
00177
00178 void GUSOut::initDev (void)
00179 {
00180 #ifdef HAVE_OSS_SUPPORT
00181 int chn;
00182 if (!ok()) return;
00183 uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7};
00184 sysex(gm_reset, sizeof(gm_reset));
00185 for (chn=0;chn<16;chn++)
00186 {
00187 chnmute[chn]=0;
00188 chnPatchChange(chn,0);
00189
00190 chnPitchBender(chn, 0x00, 0x40);
00191 chnController(chn, CTL_MAIN_VOLUME,127);
00192 chnController(chn, CTL_EXT_EFF_DEPTH, 0);
00193 chnController(chn, CTL_CHORUS_DEPTH, 0);
00194 chnController(chn, 0x4a, 127);
00195 }
00196
00197
00198 for (int i = 0; i < nvoices; i++)
00199 {
00200 SEQ_CONTROL(device, i, SEQ_VOLMODE, VOL_METHOD_LINEAR);
00201 SEQ_STOP_NOTE(device, i, vm->note(i), 64);
00202 }
00203
00204 #endif
00205 }
00206
00207
00208 int GUSOut::patch(int p)
00209 {
00210 if (patchloaded[p]==1) return p;
00211 printfdebug("Not loaded %d!\n",p);
00212 p=0;
00213 while ((p<256)&&(patchloaded[p]==0)) p++;
00214 return p;
00215 }
00216
00217 void GUSOut::noteOn (uchar chn, uchar note, uchar vel)
00218 {
00219 if (vel==0)
00220 {
00221 noteOff(chn,note,vel);
00222 }
00223 else
00224 {
00225 if (chn==PERCUSSION_CHANNEL)
00226 {
00227 if (patchloaded[note+128]==0) return;
00228 else
00229 if (patchloaded[chnpatch[chn]]==0) return;
00230 };
00231 int v=vm->allocateVoice(chn,note);
00232 int p;
00233 if (chn==PERCUSSION_CHANNEL)
00234 SEQ_SET_PATCH(device,v ,p=patch(note+128))
00235 else
00236 SEQ_SET_PATCH(device,v ,p=map->patch(chn,chnpatch[chn]));
00237 SEQ_BENDER(device, v, chnbender[chn]);
00238
00239 SEQ_START_NOTE(device, v, note, vel);
00240
00241 SEQ_CHN_PRESSURE(device, v , chnpressure[chn]);
00242 }
00243
00244 printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
00245 }
00246
00247 void GUSOut::noteOff (uchar chn, uchar note, uchar vel)
00248 {
00249 int i;
00250 vm->initSearch();
00251 while ((i=vm->search(chn,note))!=-1)
00252 {
00253 SEQ_STOP_NOTE(device, i, note, vel);
00254 vm->deallocateVoice(i);
00255 }
00256
00257 #ifdef GUSOUTDEBUG
00258 printf("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
00259 #endif
00260 }
00261
00262 void GUSOut::keyPressure (uchar chn, uchar note, uchar vel)
00263 {
00264 int i;
00265 vm->initSearch();
00266 while ((i=vm->search(chn,note))!=-1)
00267 SEQ_KEY_PRESSURE(device, i, note,vel);
00268 }
00269
00270 void GUSOut::chnPatchChange (uchar chn, uchar patch)
00271 {
00272 if (chn==PERCUSSION_CHANNEL) return;
00273 int i;
00274 vm->initSearch();
00275 while ((i=vm->search(chn))!=-1)
00276 SEQ_SET_PATCH(device,i,map->patch(chn,patch));
00277 chnpatch[chn]=patch;
00278
00279 }
00280
00281 void GUSOut::chnPressure (uchar , uchar )
00282 {
00283
00284
00285
00286
00287
00288
00289 }
00290
00291 void GUSOut::chnPitchBender(uchar chn,uchar lsb, uchar msb)
00292 {
00293 chnbender[chn]=((int)msb<<7) | (lsb & 0x7F);
00294
00295 int i;
00296 vm->initSearch();
00297 while ((i=vm->search(chn))!=-1)
00298 SEQ_BENDER(device, i, chnbender[chn]);
00299 }
00300
00301 void GUSOut::chnController (uchar chn, uchar ctl, uchar v)
00302 {
00303 if ((ctl==11)||(ctl==7))
00304 {
00305 v=(v*volumepercentage)/100;
00306 if (v>127) v=127;
00307 };
00308
00309 int i;
00310 vm->initSearch();
00311 while ((i=vm->search(chn))!=-1)
00312 SEQ_CONTROL(device, i, ctl, v);
00313
00314 chncontroller[chn][ctl]=v;
00315 }
00316
00317 void GUSOut::sysex(uchar *, ulong )
00318 {
00319
00320 }
00321
00322 void GUSOut::setGUSPatchesDirectory(const char *dir)
00323 {
00324 if ((dir==NULL)||(dir[0]==0)) return;
00325 if (delete_GUS_patches_directory)
00326 free((char *)GUS_patches_directory);
00327
00328 GUS_patches_directory = strdup(dir);
00329 delete_GUS_patches_directory=1;
00330 }
00331
00332 char *GUSOut::patchName(int pgm)
00333 {
00334 return GUS_voice_names[pgm];
00335 }
00336
00337
00338 int GUSOut::loadPatch(int pgm)
00339 {
00340 #ifdef HAVE_OSS_SUPPORT
00341 struct pat_header header;
00342 struct sample_header sample;
00343 if (patchloaded[pgm]==1)
00344 {
00345 #ifdef GUSOUTDEBUG
00346 printf("Trying to reload a patch. This should never happen, please report.\n");
00347 #endif
00348 return 0;
00349 }
00350 if ((patchName(pgm)==NULL)||((patchName(pgm))[0]==0))
00351 {
00352 #ifdef GUSOUTDEBUG
00353 printf("Couldn't guess patch name for patch number %d\n",pgm);
00354 #endif
00355 return -1;
00356 }
00357 char *s=new char[strlen(GUS_patches_directory)+strlen(patchName(pgm))+10];
00358 if (s==NULL) return -1;
00359 sprintf(s,"%s/%s.pat",GUS_patches_directory,patchName(pgm));
00360 #ifdef GUSOUTDEBUG
00361 printf("Loading patch : %s\n",s);
00362 #endif
00363 struct patch_info *patch=NULL;
00364 struct stat info;
00365 if (stat(s, &info)==-1)
00366 {
00367 #ifdef GUSOUTDEBUG
00368 printf("File %s doesn't exist\n",s);
00369 #endif
00370 return -1;
00371 }
00372
00373 FILE *fh=fopen(s,"rb");
00374 if (fh==NULL)
00375 {
00376 #ifdef GUSOUTDEBUG
00377 printf("Couldn't open patch %s\n",s);
00378 #endif
00379 return -1;
00380 }
00381
00382 unsigned char tmp[256];
00383 if (fread(tmp,1,0xef,fh)!=0xef)
00384 {
00385 fclose(fh);
00386 #ifdef GUSOUTDEBUG
00387 printf("Short file ! \n");
00388 #endif
00389 return -1;
00390 }
00391 memcpy ((char *) &header, tmp, sizeof (header));
00392
00393 if (strncmp(header.magic,"GF1PATCH110",12)!=0)
00394 {
00395 #ifdef GUSOUTDEBUG
00396 printf("File %s is corrupted or it isn't a patch file\n",s);
00397 #endif
00398 return -1;
00399 }
00400 if (strncmp(header.version,"ID#000002",10)!=0)
00401 {
00402 #ifdef GUSOUTDEBUG
00403 printf("File %s's version is not supported\n",s);
00404 #endif
00405 return -1;
00406 }
00407 unsigned short nWaves= *(unsigned short *)&tmp[85];
00408 #ifdef GUSOUTDEBUG
00409 unsigned short masterVolume= *(unsigned short *)&tmp[87];
00410 printf("nWaves: %d\n",nWaves);
00411 printf("masterVolume : %d\n",masterVolume);
00412 #endif
00413
00414 unsigned short i;
00415 int offset=0xef;
00416 for (i=0;i<nWaves;i++)
00417 {
00418 fseek(fh,offset,SEEK_SET);
00419
00420 if (fread(tmp,1,sizeof(sample),fh) != sizeof(sample))
00421 {
00422 fclose(fh);
00423 #ifdef GUSOUTDEBUG
00424 printf("Short file\n");
00425 #endif
00426 return -1;
00427 }
00428 memcpy ((char *) &sample, tmp, sizeof (sample));
00429 sample.fractions = (char)tmp[7];
00430 sample.len = get_dint(&tmp[8]);
00431 sample.loop_start = get_dint(&tmp[12]);
00432 sample.loop_end = get_dint(&tmp[16]);
00433 sample.base_freq = get_word(&tmp[20]);
00434 sample.low_note = get_dint(&tmp[22]);
00435 sample.high_note = get_dint(&tmp[26]);
00436 sample.base_note = get_dint(&tmp[30]);
00437 sample.detune = (short)get_word(&tmp[34]);
00438 sample.panning = (unsigned char) tmp[36];
00439
00440 memcpy (sample.envelope_rate, &tmp[37], 6);
00441 memcpy (sample.envelope_offset, &tmp[43], 6);
00442
00443 sample.tremolo_sweep = (unsigned char) tmp[49];
00444 sample.tremolo_rate = (unsigned char) tmp[50];
00445 sample.tremolo_depth = (unsigned char) tmp[51];
00446
00447 sample.vibrato_sweep = (unsigned char) tmp[52];
00448 sample.vibrato_rate = (unsigned char) tmp[53];
00449 sample.vibrato_depth = (unsigned char) tmp[54];
00450 sample.modes = (unsigned char) tmp[55];
00451 sample.scale_frequency = (short)get_word(&tmp[56]);
00452 sample.scale_factor = get_word(&tmp[58]);
00453
00454 offset = offset + 96;
00455
00456 patch = (struct patch_info *) malloc(sizeof (*patch) + sample.len);
00457 if (patch == NULL)
00458 {
00459 #ifdef GUSOUTDEBUG
00460 printf("Not enough memory\n");
00461 #endif
00462 return -1;
00463 }
00464 patch->key = GUS_PATCH;
00465 patch->device_no = device;
00466 patch->instr_no = pgm;
00467 patch->mode = sample.modes | WAVE_TREMOLO | WAVE_VIBRATO | WAVE_SCALE;
00468 patch->len = sample.len;
00469 patch->loop_start = sample.loop_start;
00470 patch->loop_end = sample.loop_end;
00471 patch->base_note = sample.base_note;
00472 patch->high_note = sample.high_note;
00473 patch->low_note = sample.low_note;
00474 patch->base_freq = sample.base_freq;
00475 patch->detuning = sample.detune;
00476 patch->panning = (sample.panning - 7) * 16;
00477
00478 memcpy (patch->env_rate, sample.envelope_rate, 6);
00479 memcpy (patch->env_offset, sample.envelope_offset, 6);
00480
00481 patch->tremolo_sweep = sample.tremolo_sweep;
00482 patch->tremolo_rate = sample.tremolo_rate;
00483 patch->tremolo_depth = sample.tremolo_depth;
00484
00485 patch->vibrato_sweep = sample.vibrato_sweep;
00486 patch->vibrato_rate = sample.vibrato_rate;
00487 patch->vibrato_depth = sample.vibrato_depth;
00488
00489 patch->scale_frequency = sample.scale_frequency;
00490 patch->scale_factor = sample.scale_factor;
00491
00492 patch->volume = header.master_volume;
00493
00494 if (fseek (fh, offset, 0) == -1)
00495 {
00496 fclose(fh);
00497 return -1;
00498 }
00499
00500 if ((long)fread (patch->data, 1,sample.len,fh) != sample.len)
00501 {
00502 #ifdef GUSOUTDEBUG
00503 printf ("Short file\n");
00504 #endif
00505 return -1;
00506 }
00507
00508 SEQ_WRPATCH (patch, sizeof (*patch) + sample.len);
00509
00510 offset = offset + sample.len;
00511
00512 }
00513 patchloaded[pgm]=1;
00514
00515 fclose(fh);
00516 free(patch);
00517 delete s;
00518 freememory = device;
00519 ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freememory);
00520 #endif
00521 return 0;
00522 }
00523
00524
00525 void GUSOut::setPatchesToUse(int *patchesused)
00526 {
00527 #ifdef HAVE_OSS_SUPPORT
00528 int k;
00529 for (k=0;k<256;k++) patchloaded[k]=0;
00530
00531 int patchesordered[256];
00532
00533
00534
00535 patchesLoadingOrder(patchesused,patchesordered);
00536
00537
00538
00539 #ifdef GUSOUTDEBUG
00540 printf("Patches used : \n");
00541 for (k=0;k<256;k++)
00542 {
00543 if (patchesused[k]!=-1) printf("%d,",patchesused[k]);
00544 }
00545 printf("\n Patches used, sorted :\n");
00546 for (k=0;k<256;k++)
00547 {
00548 if (patchesordered[k]!=-1) printf("%d,",patchesordered[k]);
00549 }
00550 #endif
00551
00552 int i=0;
00553 while (patchesordered[i]!=-1)
00554 {
00555 #ifdef GUSOUTDEBUG
00556 printf("Load Patch : %d\n",patchesordered[i]);
00557 #endif
00558 loadPatch(patchesordered[i]);
00559 i++;
00560 }
00561 #endif
00562 }
00563
00564 int compare_decreasing(const void *a,const void *b)
00565 {
00566 struct instr_gm
00567 {
00568 int used;
00569 int pgm;
00570 };
00571 instr_gm *ai=(instr_gm *)a;
00572 instr_gm *bi=(instr_gm *)b;
00573 return ai->used<bi->used;
00574 }
00575
00576
00577 void GUSOut::patchesLoadingOrder(int *patchesused,int *patchesordered)
00578 {
00579 struct instr_gm
00580 {
00581 int used;
00582 int pgm;
00583 };
00584
00585 instr_gm tempmelody[128];
00586 instr_gm tempdrums[128];
00587 int i,j;
00588 for (i=0,j=128;i<128;i++,j++)
00589 {
00590 tempmelody[i].used=patchesused[i];
00591 tempmelody[i].pgm=i;
00592 tempdrums[i].used=patchesused[j];
00593 tempdrums[i].pgm=j;
00594 }
00595
00596 qsort(&tempmelody[0],128,sizeof(instr_gm),compare_decreasing);
00597 qsort(&tempdrums[0],128,sizeof(instr_gm),compare_decreasing);
00598
00599
00600
00601
00602
00603
00604
00605
00606 #ifdef GUSOUTDEBUG
00607 for (int k=0;k<128;k++)
00608 {
00609 printf("%d - %d\n",tempmelody[k].used,tempmelody[k].pgm);
00610 }
00611 for (int k=0;k<128;k++)
00612 {
00613 printf("%d : %d\n",tempdrums[k].used,tempdrums[k].pgm);
00614 }
00615 #endif
00616
00617 i=0;
00618 int totalmelody=0;
00619 while ((i<128)&&(tempmelody[i].used!=0))
00620 {
00621 totalmelody++;
00622 i++;
00623 }
00624 i=0;
00625 int totaldrums=0;
00626 while ((i<128)&&(tempdrums[i].used!=0))
00627 {
00628 totaldrums++;
00629 i++;
00630 }
00631 #ifdef GUSOUTDEBUG
00632 printf("Totalmelody : %d,totaldrums : %d\n",totalmelody,totaldrums);
00633 #endif
00634 int tgt=0;
00635
00636 int tm=totalmelody;
00637 int td=totaldrums;
00638 int cm,cd;
00639 cm=cd=0;
00640 if ((tm!=0)&&(td!=0))
00641 {
00642 patchesordered[0]=tempmelody[0].pgm;
00643 patchesordered[1]=tempdrums[0].pgm;
00644 tm--;td--;
00645 cm++;cd++;
00646 tgt+=2;
00647 while ((tm>0)&&(td>0))
00648 {
00649 if (((tgt-1)%3)==0)
00650 {
00651 patchesordered[tgt]=tempdrums[cd].pgm;
00652 cd++;
00653 td--;
00654 }
00655 else
00656 {
00657 patchesordered[tgt]=tempmelody[cm].pgm;
00658 cm++;
00659 tm--;
00660 }
00661 tgt++;
00662 }
00663 }
00664 while (tm>0)
00665 {
00666 patchesordered[tgt]=tempmelody[cm].pgm;
00667 tgt++;
00668 cm++;
00669 tm--;
00670 }
00671 while (td>0)
00672 {
00673 patchesordered[tgt]=tempdrums[cd].pgm;
00674 tgt++;
00675 cd++;
00676 td--;
00677 }
00678
00679
00680 while (tgt<256)
00681 {
00682 patchesordered[tgt]=-1;
00683 tgt++;
00684 }
00685 }
00686
00687
00688 const char *GUSOut::GUS_patches_directory="/usr/share/ultrasnd";
00689
00690 int GUSOut::delete_GUS_patches_directory = 0;
00691