• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • libtdemid
 

libtdemid

  • libtdemid
fmout.cpp
1/**************************************************************************
2
3 fmout.cpp - class fmOut which handles the /dev/sequencer device
4 for fm synths
5 This file is part of LibKMid 0.9.5
6 Copyright (C) 1998,99,2000 Antonio Larrosa Jimenez
7 LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libtdemid.html
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
18
19 You should have received a copy of the GNU Library General Public License
20 along with this library; see the file COPYING.LIB. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23
24 Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org>
25
26***************************************************************************/
27#include "fmout.h"
28#include <unistd.h>
29#include <fcntl.h>
30#include <stdio.h>
31#include "sndcard.h"
32#include <sys/ioctl.h>
33#include <errno.h>
34#include <string.h>
35#include <sys/param.h>
36#include <stdlib.h>
37#include <limits.h>
38#include "midispec.h"
39#ifdef HAVE_CONFIG_H
40#include <config.h>
41#endif
42
43SEQ_USE_EXTBUF();
44
45FMOut::FMOut( int d, int total )
46{
47 seqfd = -1;
48 devicetype = KMID_FM;
49 device = d;
50 _ok = 1;
51 // Put opl=3 for opl/3 (better quality/ 6 voices)
52 // or opl=2 for fm output (less quality/ 18 voices, which is better imho) :
53 opl = 2;
54 // But be aware that opl=3 is not intended to be fully supported by now
55
56 nvoices = total;
57 vm = new VoiceManager (nvoices);
58}
59
60FMOut::~FMOut()
61{
62 closeDev();
63 delete vm;
64 if (deleteFMPatchesDirectory)
65 {
66 free((char *)FMPatchesDirectory);
67 deleteFMPatchesDirectory = 0;
68 FMPatchesDirectory="/etc";
69 }
70}
71
72void FMOut::openDev (int sqfd)
73{
74#ifdef HAVE_OSS_SUPPORT
75 _ok=1;
76 seqfd = sqfd;
77 //vm->clearLists();
78 if ( seqfd == -1 )
79 {
80 printfdebug("ERROR: Could not open /dev/sequencer\n");
81 return;
82 }
83
84 loadFMPatches();
85#endif
86
87}
88
89void FMOut::closeDev (void)
90{
91 if (!ok()) return;
92 vm->clearLists();
93 //if (seqfd>=0) close(seqfd);
94 seqfd = -1;
95}
96
97void FMOut::initDev (void)
98{
99#ifdef HAVE_OSS_SUPPORT
100 int chn;
101 if (!ok()) return;
102 uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7};
103 sysex(gm_reset, sizeof(gm_reset));
104 for (chn=0;chn<16;chn++)
105 {
106 chnmute[chn]=0;
107 chnPatchChange(chn,0);
108 chnPressure(chn,127);
109 chnPitchBender(chn, 0x00, 0x40);
110 chnController(chn, CTL_MAIN_VOLUME,127);
111 chnController(chn, CTL_EXT_EFF_DEPTH, 0);
112 chnController(chn, CTL_CHORUS_DEPTH, 0);
113 chnController(chn, 0x4a, 127);
114 }
115
116 if (opl==3) ioctl(seqfd, SNDCTL_FM_4OP_ENABLE, &device);
117 SEQ_VOLUME_MODE(device,VOL_METHOD_LINEAR);
118
119 for (int i = 0; i < nvoices; i++)
120 {
121 SEQ_CONTROL(device, i, SEQ_VOLMODE, VOL_METHOD_LINEAR);
122 SEQ_STOP_NOTE(device, i, vm->note(i), 64);
123 }
124#endif
125}
126
127void FMOut::loadFMPatches(void)
128{
129#ifdef HAVE_OSS_SUPPORT
130 char patchesfile[strlen(FMPatchesDirectory)+7+1];
131 char drumsfile[strlen(FMPatchesDirectory)+9+1];
132 int size;
133 struct sbi_instrument instr;
134 char tmp[60];
135 int i,j;
136 for ( i=0; i<256; i++ )
137 patchloaded[i] = 0;
138 int stereoeffect=rand()%3;
139 FILE *fh;
140 int datasize;
141
142 if (opl==3)
143 {
144 snprintf(patchesfile, sizeof(patchesfile), "%s/std.o3",FMPatchesDirectory);
145 size=60;
146 }
147 else
148 {
149 snprintf(patchesfile, sizeof(patchesfile), "%s/std.sb",FMPatchesDirectory);
150 size=52;
151 }
152 fh=fopen(patchesfile,"rb");
153 if (fh==NULL) return;
154
155 for (i=0;i<128;i++)
156 {
157 fread(tmp,size,1,fh);
158 patchloaded[i]=1;
159 instr.key = ((strncmp(tmp, "4OP", 3) == 0))? OPL3_PATCH : FM_PATCH;
160 datasize = (strncmp(tmp, "4OP", 3) == 0)? 22 : 11;
161 instr.device=device;
162 instr.channel = i;
163 // Let's get some stereo effect ...
164 tmp[46] = (tmp[46] & 0xcf) | ((++stereoeffect)<<4);
165 stereoeffect=stereoeffect%3;
166 for (j=0; j<22; j++)
167 instr.operators[j] = tmp[j+36];
168 SEQ_WRPATCH(&instr,sizeof(instr));
169 }
170 fclose(fh);
171
172 if (opl==3)
173 {
174 snprintf(drumsfile, sizeof(drumsfile), "%s/drums.o3",FMPatchesDirectory);
175 }
176 else
177 {
178 snprintf(drumsfile, sizeof(drumsfile), "%s/drums.sb",FMPatchesDirectory);
179 }
180
181 fh=fopen(drumsfile,"rb");
182 if (fh==NULL) return;
183
184 for (i=128;i<175;i++)
185 {
186 fread(tmp,size,1,fh);
187 patchloaded[i]=1;
188 instr.key = (strncmp(tmp, "4OP", 3) == 0)? OPL3_PATCH : FM_PATCH;
189 datasize = (strncmp(tmp, "4OP", 3) == 0)? 22 : 11;
190 instr.device=device;
191 instr.channel = i;
192 // Let's get some stereo effect ...
193 tmp[46] = (tmp[46] & 0xcf) | ((++stereoeffect)<<4);
194 stereoeffect=stereoeffect%3;
195 for (j=0; j<22; j++)
196 instr.operators[j] = tmp[j+36];
197 SEQ_WRPATCH(&instr,sizeof(instr));
198 }
199 fclose(fh);
200
201#ifdef FMOUTDEBUG
202 printfdebug("Patches loaded\n");
203#endif
204#endif
205}
206
207int FMOut::patch(int p)
208{
209 if (patchloaded[p]==1) return p;
210#ifdef FMOUTDEBUG
211 printfdebug("Not loaded %d!\n",p);
212#endif
213 p=0;
214 while ((p<256)&&(patchloaded[p]==0)) p++;
215 return p;
216}
217
218void FMOut::noteOn (uchar chn, uchar note, uchar vel)
219{
220 if (vel==0)
221 {
222 noteOff(chn,note,vel);
223 }
224 else
225 {
226 if (chn==PERCUSSION_CHANNEL)
227 {
228 if (patchloaded[note+128]==0) return;
229 else
230 if (patchloaded[chnpatch[chn]]==0) return;
231 }
232 int v=vm->allocateVoice(chn,note);
233 int p;
234 if (chn==PERCUSSION_CHANNEL)
235 SEQ_SET_PATCH(device,v ,p=patch(note+128))
236 else
237 SEQ_SET_PATCH(device,v ,p=map->patch(chn,chnpatch[chn]));
238 SEQ_BENDER(device, v, chnbender[chn]);
239
240 SEQ_START_NOTE(device, v, note, vel);
241 // SEQ_CONTROL(device, v, CTL_MAIN_VOLUME, chncontroller[chn][CTL_MAIN_VOLUME]);
242
243 SEQ_CHN_PRESSURE(device, v , chnpressure[chn]);
244 }
245
246#ifdef FMOUTDEBUG
247 printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
248#endif
249}
250
251void FMOut::noteOff (uchar chn, uchar note, uchar vel)
252{
253 int i;
254 vm->initSearch();
255 while ((i=vm->search(chn,note))!=-1)
256 {
257 SEQ_STOP_NOTE(device, i, note, vel);
258 vm->deallocateVoice(i);
259 }
260
261#ifdef FMOUTDEBUG
262 printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
263#endif
264}
265
266void FMOut::keyPressure (uchar chn, uchar note, uchar vel)
267{
268 int i;
269 vm->initSearch();
270 while ((i=vm->search(chn,note))!=-1)
271 SEQ_KEY_PRESSURE(device, i, note,vel);
272}
273
274void FMOut::chnPatchChange (uchar chn, uchar patch)
275{
276 if (chn==PERCUSSION_CHANNEL) return;
277 int i;
278 vm->initSearch();
279 while ((i=vm->search(chn))!=-1)
280 SEQ_SET_PATCH(device,i,map->patch(chn,patch));
281
282 chnpatch[chn]=patch;
283}
284
285void FMOut::chnPressure (uchar chn, uchar vel)
286{
287 int i;
288 vm->initSearch();
289 while ((i=vm->search(chn))!=-1)
290 SEQ_CHN_PRESSURE(device, i , vel);
291
292 chnpressure[chn]=vel;
293}
294
295void FMOut::chnPitchBender(uchar chn,uchar lsb, uchar msb)
296{
297 chnbender[chn]=((int)msb<<7) | (lsb & 0x7F);
298
299 int i;
300 vm->initSearch();
301 while ((i=vm->search(chn))!=-1)
302 SEQ_BENDER(device, i, chnbender[chn]);
303
304}
305
306void FMOut::chnController (uchar chn, uchar ctl, uchar v)
307{
308 if ((ctl==11)||(ctl==7))
309 {
310 v=(v*volumepercentage)/100;
311 if (v>127) v=127;
312 }
313 int i;
314 vm->initSearch();
315 while ((i=vm->search(chn))!=-1)
316 SEQ_CONTROL(device, i, ctl, v);
317
318 chncontroller[chn][ctl]=v;
319}
320
321void FMOut::sysex(uchar *, ulong )
322{
323
324}
325
326void FMOut::setFMPatchesDirectory(const char *dir)
327{
328 if ((dir==NULL)||(dir[0]==0)) return;
329 if (deleteFMPatchesDirectory)
330 free((char *)FMPatchesDirectory);
331
332 FMPatchesDirectory = strdup(dir);
333
334 deleteFMPatchesDirectory=1;
335}
336
337void FMOut::setVolumePercentage ( int i )
338{
339#ifdef HAVE_OSS_SUPPORT
340 int fd=open("/dev/mixer0",O_RDWR,0);
341 if (fd==-1) return;
342 int a=i*255/100;
343 if (a>255) a=255;
344 a=(a<<8) | a;
345 if (ioctl(fd,MIXER_WRITE(SOUND_MIXER_SYNTH),&a) == -1)
346 printfdebug("ERROR writing to mixer\n");
347 close(fd);
348#endif
349 volumepercentage=i;
350}
351
352
353const char *FMOut::FMPatchesDirectory = "/etc";
354int FMOut::deleteFMPatchesDirectory = 0;
FMOut::setFMPatchesDirectory
static void setFMPatchesDirectory(const char *dir)
Sets the directory where the FM patches are stored, that is, where the std.o3, std....
Definition: fmout.cpp:326
FMOut::initDev
virtual void initDev(void)
See MidiOut::initDev()
Definition: fmout.cpp:97
FMOut::patch
int patch(int p)
Returns p if the patch p has been loaded, or another patch (already loaded) if p hasn't been loaded.
Definition: fmout.cpp:207
FMOut::chnPatchChange
virtual void chnPatchChange(uchar chn, uchar patch)
See MidiOut::chnPatchChange()
Definition: fmout.cpp:274
FMOut::keyPressure
virtual void keyPressure(uchar chn, uchar note, uchar vel)
See MidiOut::keyPressure()
Definition: fmout.cpp:266
FMOut::openDev
virtual void openDev(int sqfd)
See MidiOut::openDev()
Definition: fmout.cpp:72
FMOut::FMOut
FMOut(int d=0, int total=12)
Constructor.
Definition: fmout.cpp:45
FMOut::noteOff
virtual void noteOff(uchar chn, uchar note, uchar vel)
See MidiOut::noteOff()
Definition: fmout.cpp:251
FMOut::sysex
virtual void sysex(uchar *data, ulong size)
It's an empty function, as FM devices don't support System Exclusive messages.
Definition: fmout.cpp:321
FMOut::noteOn
virtual void noteOn(uchar chn, uchar note, uchar vel)
See MidiOut::noteOn()
Definition: fmout.cpp:218
FMOut::setVolumePercentage
virtual void setVolumePercentage(int i)
See MidiOut::setVolumePercentage()
Definition: fmout.cpp:337
FMOut::closeDev
virtual void closeDev(void)
See MidiOut::closeDev()
Definition: fmout.cpp:89
FMOut::chnPitchBender
virtual void chnPitchBender(uchar chn, uchar lsb, uchar msb)
See MidiOut::chnPitchBender()
Definition: fmout.cpp:295
FMOut::chnPressure
virtual void chnPressure(uchar chn, uchar vel)
See MidiOut::chnPressure()
Definition: fmout.cpp:285
FMOut::~FMOut
~FMOut()
Destructor.
Definition: fmout.cpp:60
FMOut::chnController
virtual void chnController(uchar chn, uchar ctl, uchar v)
See MidiOut::chnController()
Definition: fmout.cpp:306
MidiMapper::patch
uchar patch(uchar chn, uchar pgm)
Returns the patch which pgm used on channel chn should be mapped to.
Definition: midimapper.cpp:431
MidiOut::ok
int ok(void)
Returns true if everything's ok and false if there has been any problem.
Definition: midiout.h:231

libtdemid

Skip menu "libtdemid"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

libtdemid

Skip menu "libtdemid"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for libtdemid by doxygen 1.9.4
This website is maintained by Timothy Pearson.