# libkmid Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# fmout.cc

    00001 /**************************************************************************
    00002
    00003     fmout.cc   - class fmOut which handles the /dev/sequencer device
    00004                         for fm synths
    00005     This file is part of LibKMid 0.9.5
    00006     Copyright (C) 1998,99,2000  Antonio Larrosa Jimenez
    00007     LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libkmid.html
    00008
    00009     This library is free software; you can redistribute it and/or
    00010     modify it under the terms of the GNU Library General Public
    00011     License as published by the Free Software Foundation; either
    00012     version 2 of the License, or (at your option) any later version.
    00013
    00014     This library is distributed in the hope that it will be useful,
    00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00017     Library General Public License for more details.
    00018
    00019     You should have received a copy of the GNU Library General Public License
    00020     along with this library; see the file COPYING.LIB.  If not, write to
    00021     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00022     Boston, MA 02111-1307, USA.
    00023
    00024     Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org>
    00025
    00026 ***************************************************************************/
    00027 #include "fmout.h"
    00028 #include <unistd.h>
    00029 #include <fcntl.h>
    00030 #include <stdio.h>
    00031 #include "sndcard.h"
    00032 #include <sys/ioctl.h>
    00033 #include <errno.h>
    00034 #include <string.h>
    00035 #include <sys/param.h>
    00036 #include <stdlib.h>
    00037 #include <limits.h>
    00038 #include "midispec.h"
    00039 #ifdef HAVE_CONFIG_H
    00040 #include <config.h>
    00041 #endif
    00042
    00043 SEQ_USE_EXTBUF();
    00044
    00045 FMOut::FMOut( int d, int total )
    00046 {
    00047   seqfd = -1;
    00048   devicetype = KMID_FM;
    00049   device = d;
    00050   _ok = 1;
    00051   // Put opl=3 for opl/3 (better quality/ 6 voices)
    00052   //  or opl=2 for fm output (less quality/ 18 voices, which is better imho) :
    00053   opl = 2;
    00054   // But be aware that opl=3 is not intended to be fully supported by now
    00055
    00056   nvoices = total;
    00057   vm = new VoiceManager (nvoices);
    00058 }
    00059
    00060 FMOut::~FMOut()
    00061 {
    00062   closeDev();
    00063   delete vm;
    00064   if (deleteFMPatchesDirectory)
    00065   {
    00066     free((char *)FMPatchesDirectory);
    00067     deleteFMPatchesDirectory = 0;
    00068     FMPatchesDirectory="/etc";
    00069   }
    00070 }
    00071
    00072 void FMOut::openDev (int sqfd)
    00073 {
    00074 #ifdef HAVE_OSS_SUPPORT
    00075   _ok=1;
    00076   seqfd = sqfd;
    00077   //vm->clearLists();
    00078   if ( seqfd == -1 )
    00079   {
    00080     printfdebug("ERROR: Could not open /dev/sequencer\n");
    00081     return;
    00082   }
    00083
    00084   loadFMPatches();
    00085 #endif
    00086
    00087 }
    00088
    00089 void FMOut::closeDev (void)
    00090 {
    00091   if (!ok()) return;
    00092   vm->clearLists();
    00093   //if (seqfd>=0) close(seqfd);
    00094   seqfd = -1;
    00095 }
    00096
    00097 void FMOut::initDev (void)
    00098 {
    00099 #ifdef HAVE_OSS_SUPPORT
    00100   int chn;
    00101   if (!ok()) return;
    00102   uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7};
    00103   sysex(gm_reset, sizeof(gm_reset));
    00104   for (chn=0;chn<16;chn++)
    00105   {
    00106     chnmute[chn]=0;
    00107     chnPatchChange(chn,0);
    00108     chnPressure(chn,127);
    00109     chnPitchBender(chn, 0x00, 0x40);
    00110     chnController(chn, CTL_MAIN_VOLUME,127);
    00111     chnController(chn, CTL_EXT_EFF_DEPTH, 0);
    00112     chnController(chn, CTL_CHORUS_DEPTH, 0);
    00113     chnController(chn, 0x4a, 127);
    00114   }
    00115
    00116   if (opl==3) ioctl(seqfd, SNDCTL_FM_4OP_ENABLE, &device);
    00117   SEQ_VOLUME_MODE(device,VOL_METHOD_LINEAR);
    00118
    00119   for (int i = 0; i < nvoices; i++)
    00120   {
    00121     SEQ_CONTROL(device, i, SEQ_VOLMODE, VOL_METHOD_LINEAR);
    00122     SEQ_STOP_NOTE(device, i, vm->note(i), 64);
    00123   }
    00124 #endif
    00125 }
    00126
    00127 void FMOut::loadFMPatches(void)
    00128 {
    00129 #ifdef HAVE_OSS_SUPPORT
    00130   char patchesfile[PATH_MAX];
    00131   char drumsfile[PATH_MAX];
    00132   int size;
    00133   struct sbi_instrument instr;
    00134   char tmp[60];
    00135   int i,j;
    00136   for ( i=0; i<256; i++ )
    00137     patchloaded[i] = 0;
    00138   int stereoeffect=rand()%3;
    00139   FILE *fh;
    00140   int datasize;
    00141
    00142   if (opl==3)
    00143   {
    00144     snprintf(patchesfile, PATH_MAX, "%s/std.o3",FMPatchesDirectory);
    00145     size=60;
    00146   }
    00147   else
    00148   {
    00149     snprintf(patchesfile, PATH_MAX, "%s/std.sb",FMPatchesDirectory);
    00150     size=52;
    00151   }
    00152   fh=fopen(patchesfile,"rb");
    00153   if (fh==NULL) return;
    00154
    00155   for (i=0;i<128;i++)
    00156   {
    00157     fread(tmp,size,1,fh);
    00158     patchloaded[i]=1;
    00159     instr.key = ((strncmp(tmp, "4OP", 3) == 0))? OPL3_PATCH : FM_PATCH;
    00160     datasize = (strncmp(tmp, "4OP", 3) == 0)? 22 : 11;
    00161     instr.device=device;
    00162     instr.channel = i;
    00163     // Let's get some stereo effect ...
    00164     tmp[46] = (tmp[46] & 0xcf) | ((++stereoeffect)<<4);
    00165     stereoeffect=stereoeffect%3;
    00166     for (j=0; j<22; j++)
    00167       instr.operators[j] = tmp[j+36];
    00168     SEQ_WRPATCH(&instr,sizeof(instr));
    00169   }
    00170   fclose(fh);
    00171
    00172   if (opl==3)
    00173   {
    00174     snprintf(drumsfile, PATH_MAX, "%s/drums.o3",FMPatchesDirectory);
    00175   }
    00176   else
    00177   {
    00178     snprintf(drumsfile, PATH_MAX, "%s/drums.sb",FMPatchesDirectory);
    00179   }
    00180
    00181   fh=fopen(drumsfile,"rb");
    00182   if (fh==NULL) return;
    00183
    00184   for (i=128;i<175;i++)
    00185   {
    00186     fread(tmp,size,1,fh);
    00187     patchloaded[i]=1;
    00188     instr.key = (strncmp(tmp, "4OP", 3) == 0)? OPL3_PATCH : FM_PATCH;
    00189     datasize = (strncmp(tmp, "4OP", 3) == 0)? 22 : 11;
    00190     instr.device=device;
    00191     instr.channel = i;
    00192     // Let's get some stereo effect ...
    00193     tmp[46] = (tmp[46] & 0xcf) | ((++stereoeffect)<<4);
    00194     stereoeffect=stereoeffect%3;
    00195     for (j=0; j<22; j++)
    00196       instr.operators[j] = tmp[j+36];
    00197     SEQ_WRPATCH(&instr,sizeof(instr));
    00198   }
    00199   fclose(fh);
    00200
    00201 #ifdef FMOUTDEBUG
    00202   printfdebug("Patches loaded\n");
    00203 #endif
    00204 #endif
    00205 }
    00206
    00207 int FMOut::patch(int p)
    00208 {
    00209   if (patchloaded[p]==1) return p;
    00210 #ifdef FMOUTDEBUG
    00211   printfdebug("Not loaded %d!\n",p);
    00212 #endif
    00213   p=0;
    00214   while ((p<256)&&(patchloaded[p]==0)) p++;
    00215   return p;
    00216 }
    00217
    00218 void FMOut::noteOn  (uchar chn, uchar note, uchar vel)
    00219 {
    00220   if (vel==0)
    00221   {
    00222     noteOff(chn,note,vel);
    00223   }
    00224   else
    00225   {
    00226     if (chn==PERCUSSION_CHANNEL)
    00227     {
    00228       if (patchloaded[note+128]==0) return;
    00229       else
    00230         if (patchloaded[chnpatch[chn]]==0) return;
    00231     }
    00232     int v=vm->allocateVoice(chn,note);
    00233     int p;
    00234     if (chn==PERCUSSION_CHANNEL)
    00235       SEQ_SET_PATCH(device,v ,p=patch(note+128))
    00236     else
    00237       SEQ_SET_PATCH(device,v ,p=map->patch(chn,chnpatch[chn]));
    00238     SEQ_BENDER(device, v, chnbender[chn]);
    00239
    00240     SEQ_START_NOTE(device, v, note, vel);
    00241     //    SEQ_CONTROL(device, v, CTL_MAIN_VOLUME, chncontroller[chn][CTL_MAIN_VOLUME]);
    00242
    00243     SEQ_CHN_PRESSURE(device, v , chnpressure[chn]);
    00244   }
    00245
    00246 #ifdef FMOUTDEBUG
    00247   printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
    00248 #endif
    00249 }
    00250
    00251 void FMOut::noteOff (uchar chn, uchar note, uchar vel)
    00252 {
    00253   int i;
    00254   vm->initSearch();
    00255   while ((i=vm->search(chn,note))!=-1)
    00256   {
    00257     SEQ_STOP_NOTE(device, i, note, vel);
    00258     vm->deallocateVoice(i);
    00259   }
    00260
    00261 #ifdef FMOUTDEBUG
    00262   printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
    00263 #endif
    00264 }
    00265
    00266 void FMOut::keyPressure (uchar chn, uchar note, uchar vel)
    00267 {
    00268   int i;
    00269   vm->initSearch();
    00270   while ((i=vm->search(chn,note))!=-1)
    00271     SEQ_KEY_PRESSURE(device, i, note,vel);
    00272 }
    00273
    00274 void FMOut::chnPatchChange (uchar chn, uchar patch)
    00275 {
    00276   if (chn==PERCUSSION_CHANNEL) return;
    00277   int i;
    00278   vm->initSearch();
    00279   while ((i=vm->search(chn))!=-1)
    00280     SEQ_SET_PATCH(device,i,map->patch(chn,patch));
    00281
    00282   chnpatch[chn]=patch;
    00283 }
    00284
    00285 void FMOut::chnPressure (uchar chn, uchar vel)
    00286 {
    00287   int i;
    00288   vm->initSearch();
    00289   while ((i=vm->search(chn))!=-1)
    00290     SEQ_CHN_PRESSURE(device, i , vel);
    00291
    00292   chnpressure[chn]=vel;
    00293 }
    00294
    00295 void FMOut::chnPitchBender(uchar chn,uchar lsb, uchar msb)
    00296 {
    00297   chnbender[chn]=((int)msb<<7) | (lsb & 0x7F);
    00298
    00299   int i;
    00300   vm->initSearch();
    00301   while ((i=vm->search(chn))!=-1)
    00302     SEQ_BENDER(device, i, chnbender[chn]);
    00303
    00304 }
    00305
    00306 void FMOut::chnController (uchar chn, uchar ctl, uchar v)
    00307 {
    00308   if ((ctl==11)||(ctl==7))
    00309   {
    00310     v=(v*volumepercentage)/100;
    00311     if (v>127) v=127;
    00312   }
    00313   int i;
    00314   vm->initSearch();
    00315   while ((i=vm->search(chn))!=-1)
    00316     SEQ_CONTROL(device, i, ctl, v);
    00317
    00318   chncontroller[chn][ctl]=v;
    00319 }
    00320
    00321 void FMOut::sysex(uchar *, ulong )
    00322 {
    00323
    00324 }
    00325
    00326 void FMOut::setFMPatchesDirectory(const char *dir)
    00327 {
    00328   if ((dir==NULL)||(dir[0]==0)) return;
    00329   if (deleteFMPatchesDirectory)
    00330         free((char *)FMPatchesDirectory);
    00331
    00332   FMPatchesDirectory = strdup(dir);
    00333
    00334   deleteFMPatchesDirectory=1;
    00335 }
    00336
    00337 void FMOut::setVolumePercentage    ( int i )
    00338 {
    00339 #ifdef HAVE_OSS_SUPPORT
    00340   int fd=open("/dev/mixer0",O_RDWR,0);
    00341   if (fd==-1) return;
    00342   int a=i*255/100;
    00343   if (a>255) a=255;
    00344   a=(a<<8) | a;
    00345   if (ioctl(fd,MIXER_WRITE(SOUND_MIXER_SYNTH),&a) == -1)
    00346     printfdebug("ERROR writing to mixer\n");
    00347   close(fd);
    00348 #endif
    00349   volumepercentage=i;
    00350 }
    00351
    00352
    00353 const char *FMOut::FMPatchesDirectory = "/etc";
    00354 int FMOut::deleteFMPatchesDirectory = 0;

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:28:29 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001