1
/**************************************************************************
3
gusout.cc - class GUSOut which implements support for Gravis
4
Ultrasound cards through a /dev/sequencer device
5
Copyright (C) 1998 Antonio Larrosa Jimenez
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
Send comments and bug fixes to antlarr@arrakis.es
22
or to Antonio Larrosa, Rio Arnoya, 10 5B, 29006 Malaga, Spain
24
***************************************************************************/
31
#include <sys/ioctl.h>
34
#include <sys/param.h>
36
#include "../version.h"
38
#include "gusvoices.h"
47
unsigned char instruments;
50
unsigned short nr_waveforms;
51
unsigned short master_volume;
52
unsigned long data_size;
57
unsigned char fractions;
61
unsigned short base_freq;
66
unsigned char panning;
68
unsigned char envelope_rate[6];
69
unsigned char envelope_offset[6];
71
unsigned char tremolo_sweep;
72
unsigned char tremolo_rate;
73
unsigned char tremolo_depth;
75
unsigned char vibrato_sweep;
76
unsigned char vibrato_rate;
77
unsigned char vibrato_depth;
81
short scale_frequency;
82
unsigned short scale_factor;
85
int get_dint(unsigned char *p)
96
unsigned short get_word(unsigned char *p)
100
for (int i=0;i<2;i++)
101
v |= (*p++ << (i*8));
105
GUSOut::GUSOut(int d,int total)
110
#ifdef HANDLETIMEINDEVICES
119
vm=new voiceManager(nvoices);
126
if (delete_GUS_patches_directory)
128
delete GUS_patches_directory;
129
delete_GUS_patches_directory = 0;
130
GUS_patches_directory="/etc";
134
void GUSOut::openDev (int sqfd)
141
printf("ERROR: Could not open /dev/sequencer\n");
145
#ifdef HANDLETIMEINDEVICES
146
ioctl(seqfd,SNDCTL_SEQ_NRSYNTHS,&ndevs);
147
ioctl(seqfd,SNDCTL_SEQ_NRMIDIS,&nmidiports);
150
int r=ioctl(seqfd,SNDCTL_SEQ_CTRLRATE,&rate);
151
if ((r==-1)||(rate<=0)) rate=HZ;
152
convertrate=1000/rate;
159
//ioctl(seqfd,SNDCTL_SEQ_RESET);
160
//ioctl(seqfd,SNDCTL_SEQ_PANIC);
162
if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &device)==-1)
164
printf("Error reseting gus samples. Please report\n");
167
totalmemory = device;
168
ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &totalmemory);
170
ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freememory);
173
printf("GUS Device %d opened (%d voices)\n",device,nvoices);
174
#ifdef HANDLETIMEINDEVICES
175
printf("Number of synth devices : %d\n",ndevs);
176
printf("Number of midi ports : %d\n",nmidiports);
177
printf("Rate : %d\n",rate);
184
void GUSOut::closeDev (void)
187
#ifdef HANDLETIMEINDEVICES
197
void GUSOut::initDev (void)
201
#ifdef HANDLETIMEINDEVICES
205
uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7};
206
sysex(gm_reset, sizeof(gm_reset));
207
for (chn=0;chn<16;chn++)
210
chnPatchChange(chn,0);
211
// chnPressure(chn,127);
212
chnPitchBender(chn, 0x00, 0x40);
213
chnController(chn, CTL_MAIN_VOLUME,127);
214
chnController(chn, CTL_EXT_EFF_DEPTH, 0);
215
chnController(chn, CTL_CHORUS_DEPTH, 0);
216
chnController(chn, 0x4a, 127);
220
for (int i = 0; i < nvoices; i++)
222
SEQ_CONTROL(device, i, SEQ_VOLMODE, VOL_METHOD_LINEAR);
223
SEQ_STOP_NOTE(device, i, vm->Note(i), 64);
229
int GUSOut::patch(int p)
231
if (patchloaded[p]==1) return p;
232
printf("Not loaded %d!\n",p);
234
while ((p<256)&&(patchloaded[p]==0)) p++;
238
void GUSOut::noteOn (uchar chn, uchar note, uchar vel)
242
noteOff(chn,note,vel);
246
if (chn==PERCUSSION_CHANNEL)
248
if (patchloaded[note+128]==0) return;
250
if (patchloaded[chnpatch[chn]]==0) return;
252
int v=vm->allocateVoice(chn,note);
254
if (chn==PERCUSSION_CHANNEL)
255
SEQ_SET_PATCH(device,v ,p=patch(note+128))
257
SEQ_SET_PATCH(device,v ,p=map->patch(chn,chnpatch[chn]));
258
SEQ_BENDER(device, v, chnbender[chn]);
260
SEQ_START_NOTE(device, v, note, vel);
261
// SEQ_CONTROL(device, v, CTL_MAIN_VOLUME, chncontroller[chn][CTL_MAIN_VOLUME]);
262
SEQ_CHN_PRESSURE(device, v , chnpressure[chn]);
266
printf("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
270
void GUSOut::noteOff (uchar chn, uchar note, uchar vel)
274
while ((i=vm->Search(chn,note))!=-1)
276
SEQ_STOP_NOTE(device, i, note, vel);
277
vm->deallocateVoice(i);
281
printf("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
285
void GUSOut::keyPressure (uchar chn, uchar note, uchar vel)
289
while ((i=vm->Search(chn,note))!=-1)
290
SEQ_KEY_PRESSURE(device, i, note,vel);
293
void GUSOut::chnPatchChange (uchar chn, uchar patch)
295
if (chn==PERCUSSION_CHANNEL) return;
298
while ((i=vm->Search(chn))!=-1)
299
SEQ_SET_PATCH(device,i,map->patch(chn,patch));
304
void GUSOut::chnPressure (uchar chn, uchar vel)
308
while ((i=vm->Search(chn))!=-1)
309
SEQ_CHN_PRESSURE(device, i , vel);
310
chnpressure[chn]=vel;
314
void GUSOut::chnPitchBender(uchar chn,uchar lsb, uchar msb)
316
chnbender[chn]=((int)msb<<7) | (lsb & 0x7F);
320
while ((i=vm->Search(chn))!=-1)
321
SEQ_BENDER(device, i, chnbender[chn]);
324
void GUSOut::chnController (uchar chn, uchar ctl, uchar v)
326
if ((ctl==11)||(ctl==7))
328
v=(v*volumepercentage)/100;
334
while ((i=vm->Search(chn))!=-1)
335
SEQ_CONTROL(device, i, ctl, v);
337
chncontroller[chn][ctl]=v;
340
void GUSOut::sysex(uchar *, ulong )
345
void GUSOut::setGUSPatchesDirectory(const char *dir)
347
if ((dir==NULL)||(dir[0]==0)) return;
348
if (delete_GUS_patches_directory) delete GUS_patches_directory;
349
char *GUS_patches_directory2=new char[strlen(dir)+1];
350
strcpy(GUS_patches_directory2,dir);
351
GUS_patches_directory = GUS_patches_directory2;
352
delete_GUS_patches_directory=1;
355
char *GUSOut::patchName(int pgm)
357
return GUS_voice_names[pgm];
361
int GUSOut::loadPatch(int pgm)
363
struct pat_header header;
364
struct sample_header sample;
365
if (patchloaded[pgm]==1)
367
printf("Trying to reload a patch. This should never happen, please report.\n");
370
if ((patchName(pgm)==NULL)||((patchName(pgm))[0]==0))
372
printf("Couldn't guess patch name for patch number %d\n",pgm);
375
char *s=new char[strlen(GUS_patches_directory)+strlen(patchName(pgm))+10];
376
if (s==NULL) return -1;
377
sprintf(s,"%s/%s.pat",GUS_patches_directory,patchName(pgm));
378
printf("Loading patch : %s\n",s);
379
struct patch_info *patch=NULL;
381
if (stat(s, &info)==-1)
383
printf("File %s doesn't exist\n",s);
387
FILE *fh=fopen(s,"rb");
390
printf("Couldn't open patch %s\n",s);
394
unsigned char tmp[256];
395
if (fread(tmp,1,0xef,fh)!=0xef)
398
printf("Short file ! \n");
401
memcpy ((char *) &header, tmp, sizeof (header));
403
if (strncmp(header.magic,"GF1PATCH110",12)!=0)
405
printf("File %s is corrupted or it isn't a patch file\n",s);
408
if (strncmp(header.version,"ID#000002",10)!=0)
410
printf("File %s's version is not supported\n",s);
413
unsigned short nWaves= *(unsigned short *)&tmp[85];
415
unsigned short masterVolume= *(unsigned short *)&tmp[87];
416
printf("nWaves: %d\n",nWaves);
417
printf("masterVolume : %d\n",masterVolume);
422
for (i=0;i<nWaves;i++)
424
fseek(fh,offset,SEEK_SET);
426
if (fread(tmp,1,sizeof(sample),fh) != sizeof(sample))
429
printf("Short file\n");
432
memcpy ((char *) &sample, tmp, sizeof (sample));
433
sample.fractions = (char)tmp[7];
434
sample.len = get_dint(&tmp[8]);
435
sample.loop_start = get_dint(&tmp[12]);
436
sample.loop_end = get_dint(&tmp[16]);
437
sample.base_freq = get_word(&tmp[20]);
438
sample.low_note = get_dint(&tmp[22]);
439
sample.high_note = get_dint(&tmp[26]);
440
sample.base_note = get_dint(&tmp[30]);
441
sample.detune = (short)get_word(&tmp[34]);
442
sample.panning = (unsigned char) tmp[36];
444
memcpy (sample.envelope_rate, &tmp[37], 6);
445
memcpy (sample.envelope_offset, &tmp[43], 6);
447
sample.tremolo_sweep = (unsigned char) tmp[49];
448
sample.tremolo_rate = (unsigned char) tmp[50];
449
sample.tremolo_depth = (unsigned char) tmp[51];
451
sample.vibrato_sweep = (unsigned char) tmp[52];
452
sample.vibrato_rate = (unsigned char) tmp[53];
453
sample.vibrato_depth = (unsigned char) tmp[54];
454
sample.modes = (unsigned char) tmp[55];
455
sample.scale_frequency = (short)get_word(&tmp[56]);
456
sample.scale_factor = get_word(&tmp[58]);
458
offset = offset + 96;
460
patch = (struct patch_info *) malloc(sizeof (*patch) + sample.len);
463
printf("Not enough memory\n");
466
patch->key = GUS_PATCH;
467
patch->device_no = device;
468
patch->instr_no = pgm;
469
patch->mode = sample.modes | WAVE_TREMOLO | WAVE_VIBRATO | WAVE_SCALE;
470
patch->len = sample.len;
471
patch->loop_start = sample.loop_start;
472
patch->loop_end = sample.loop_end;
473
patch->base_note = sample.base_note;
474
patch->high_note = sample.high_note;
475
patch->low_note = sample.low_note;
476
patch->base_freq = sample.base_freq;
477
patch->detuning = sample.detune;
478
patch->panning = (sample.panning - 7) * 16;
480
memcpy (patch->env_rate, sample.envelope_rate, 6);
481
memcpy (patch->env_offset, sample.envelope_offset, 6);
483
patch->tremolo_sweep = sample.tremolo_sweep;
484
patch->tremolo_rate = sample.tremolo_rate;
485
patch->tremolo_depth = sample.tremolo_depth;
487
patch->vibrato_sweep = sample.vibrato_sweep;
488
patch->vibrato_rate = sample.vibrato_rate;
489
patch->vibrato_depth = sample.vibrato_depth;
491
patch->scale_frequency = sample.scale_frequency;
492
patch->scale_factor = sample.scale_factor;
494
patch->volume = header.master_volume;
496
if (fseek (fh, offset, 0) == -1)
502
if ((long)fread (patch->data, 1,sample.len,fh) != sample.len)
504
printf ("Short file\n");
508
SEQ_WRPATCH (patch, sizeof (*patch) + sample.len);
510
offset = offset + sample.len;
516
free(patch); // Shouldn't this 'free' be within the 'for' loop ?
519
ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freememory);
524
void GUSOut::setPatchesToUse(int *patchesused)
527
for (k=0;k<256;k++) patchloaded[k]=0;
529
int patchesordered[256]; //This holds the pgm used ordered by a method which
530
// put first the patches more oftenly used, and then the least
531
// In example, if a song only uses a piano and a splash cymbal,
532
// This is set to : 0,188,-1,-1,-1,-1 ...
533
getPatchesLoadingOrder(patchesused,patchesordered);
535
// If above line doesn't work, perhaps you could try this ? :
536
// for (int j=0;j<256;j++) patchesordered[j]=patchesused[j];
537
printf("Patches used : \n");
540
if (patchesused[k]!=-1) printf("%d,",patchesused[k]);
542
printf("\n Patches used, sorted :\n");
545
if (patchesordered[k]!=-1) printf("%d,",patchesordered[k]);
549
while (patchesordered[i]!=-1)
551
printf("Load Patch : %d\n",patchesordered[i]);
552
loadPatch(patchesordered[i]);
557
int compare_decreasing(const void *a,const void *b)
564
instr_gm *ai=(instr_gm *)a;
565
instr_gm *bi=(instr_gm *)b;
566
return ai->used<bi->used;
569
void GUSOut::getPatchesLoadingOrder(int *patchesused,int *patchesordered)
577
instr_gm tempmelody[128];
578
instr_gm tempdrums[128];
580
for (i=0,j=128;i<128;i++,j++)
582
tempmelody[i].used=patchesused[i];
584
tempdrums[i].used=patchesused[j];
587
/* SORT */ // Decreasing order (first most used patch, then less used patch)
588
qsort(&tempmelody[0],128,sizeof(instr_gm),compare_decreasing);
589
qsort(&tempdrums[0],128,sizeof(instr_gm),compare_decreasing);
591
/* Once they are sorted, the result is put on patchesordered in the following
592
way : If tempmelody is : M0 M1 M2 M3 ... M127 and tempdrums is :
593
D0 D1 D2 D3 ... D127, the result is :
594
M0 D0 M1 M2 D1 M3 M4 D2 M5 M6 D3 ...
595
P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 P10 ...
599
for (int k=0;k<128;k++)
601
printf("%d - %d\n",tempmelody[k].used,tempmelody[k].pgm);
603
for (int k=0;k<128;k++)
605
printf("%d : %d\n",tempdrums[k].used,tempdrums[k].pgm);
611
while ((i<128)&&(tempmelody[i].used!=0))
618
while ((i<128)&&(tempdrums[i].used!=0))
623
printf("Totalmelody : %d,totaldrums : %d\n",totalmelody,totaldrums);
630
if ((tm!=0)&&(td!=0))
632
patchesordered[0]=tempmelody[0].pgm;
633
patchesordered[1]=tempdrums[0].pgm;
637
while ((tm>0)&&(td>0))
641
patchesordered[tgt]=tempdrums[cd].pgm;
647
patchesordered[tgt]=tempmelody[cm].pgm;
656
patchesordered[tgt]=tempmelody[cm].pgm;
663
patchesordered[tgt]=tempdrums[cd].pgm;
669
// Now we put as not used (-1) the rest of the array
672
patchesordered[tgt]=-1;
677
//char *GUSOut::GUS_patches_directory="/mnt/dosc/gravis/patches";
678
const char *GUSOut::GUS_patches_directory="/dos/ultrasnd/midi";
680
int GUSOut::delete_GUS_patches_directory = 0;
681
/* No, this doesn't delete any file :-) it's just for internal use */