libkmid Library API Documentation

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;
KDE Logo
This file is part of the documentation for libkmid Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Oct 8 11:15:25 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003