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

libtdemid

  • libtdemid
alsaout.cpp
1/**************************************************************************
2
3 alsaout.cpp - class AlsaOut which represents an alsa client/port pair
4 This file is part of LibKMid 0.9.5
5 Copyright (C) 2000 Antonio Larrosa Jimenez
6 LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libtdemid.html
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22
23 Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org>
24
25***************************************************************************/
26#include "alsaout.h"
27#include <unistd.h>
28#include <fcntl.h>
29#include <stdio.h>
30#include "sndcard.h"
31#include <errno.h>
32#include <string.h>
33#include <stdlib.h>
34#include <sys/param.h>
35#include "midispec.h"
36
37
38#ifdef HAVE_CONFIG_H
39#include <config.h>
40#endif
41
42#ifdef HAVE_ALSA_ASOUNDLIB_H
43# include <alsa/asoundlib.h>
44#elif defined(HAVE_SYS_ASOUNDLIB_H)
45# include <sys/asoundlib.h>
46#endif
47
48#ifdef HAVE_LIBASOUND2
49# define HAVE_ALSA_SEQ 1
50# define snd_seq_flush_output(x) snd_seq_drain_output(x)
51#elif defined(HAVE_LIBASOUND)
52# define HAVE_ALSA_SEQ 1
53# include <linux/asequencer.h>
54#endif
55
56
57SEQ_USE_EXTBUF();
58
59class AlsaOut::AlsaOutPrivate
60{
61public:
62#ifdef HAVE_ALSA_SEQ
63 AlsaOutPrivate(int _client, int _port, const char *cname,const char *pname)
64 {
65 handle=0L;
66 src=tgt=0L;
67 queue=0;
68 tPCN=1;
69 tgtclient=_client;
70 tgtport=_port;
71 tgtname=new char[strlen(cname)+strlen(pname)+3];
72 strcpy(tgtname, cname);
73 strcat(tgtname, " ");
74 strcat(tgtname, pname);
75 ev=new snd_seq_event_t;
76 timerStarted=false;
77 }
78#else
79 AlsaOutPrivate(int, int, const char *,const char *)
80 {
81 }
82#endif
83
84 ~AlsaOutPrivate()
85 {
86#ifdef HAVE_ALSA_SEQ
87 delete ev;
88 delete tgtname;
89#endif
90 }
91
92#ifdef HAVE_ALSA_SEQ
93 snd_seq_t *handle;
94 int client;
95 int queue;
96 snd_seq_addr_t *src;
97 snd_seq_addr_t *tgt;
98
99 snd_seq_event_t *ev;
100 int tPCN;
101
102 int tgtclient;
103 int tgtport;
104 char *tgtname;
105
106 bool timerStarted;
107
108#endif
109};
110
111AlsaOut::AlsaOut(int d,int _client, int _port, const char *cname,const char *pname) : MidiOut (d)
112{
113 di = new AlsaOutPrivate( _client, _port, cname, pname);
114 seqfd = 0;
115 devicetype=KMID_ALSA;
116 device= d;
117
118 volumepercentage=100;
119#ifdef HAVE_ALSA_SEQ
120// printf("%d %d %d (%s)\n",device, di->tgtclient, di->tgtport, di->tgtname);
121#endif
122
123 _ok=1;
124}
125
126AlsaOut::~AlsaOut()
127{
128 closeDev();
129 delete di;
130}
131
132void AlsaOut::openDev (int)
133{
134#ifndef HAVE_ALSA_SEQ
135 return;
136#else
137 _ok=1;
138#ifdef HAVE_LIBASOUND2
139 if (snd_seq_open(&di->handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0)
140 fprintf(stderr, "Couldn't open sequencer: %s", snd_strerror(errno));
141#else
142 if (snd_seq_open(&di->handle, SND_SEQ_OPEN) < 0)
143 fprintf(stderr, "Couldn't open sequencer: %s", snd_strerror(errno));
144#endif
145
146 di->queue = snd_seq_alloc_queue(di->handle);
147 if (di->queue < 0) {fprintf(stderr, "Couldn't allocate queue"); return; };
148 di->client = snd_seq_client_id(di->handle);
149 if (di->client < 0) {fprintf(stderr, "Couldn't get client id"); return; };
150 di->tgt = new snd_seq_addr_t;
151 di->tgt->client=di->tgtclient;
152 di->tgt->port=di->tgtport;
153
154 di->src = new snd_seq_addr_t;
155 di->src->client = di->client;
156 int port = snd_seq_create_simple_port(di->handle, NULL,
157 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE
158 | SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC);
159 if ( port < 0 )
160 {
161 delete di->src;
162 delete di->tgt;
163 di->src=0;
164 di->tgt=0;
165 _ok=0;
166 time=0;
167 snd_seq_free_queue(di->handle, di->queue);
168 snd_seq_close(di->handle);
169 fprintf(stderr, "Cannot connect to %d:%d\n",di->tgtclient,di->tgtport);
170 return;
171 }
172 di->src->port = port;
173
174
175 int r=snd_seq_connect_to(di->handle, di->src->port, di->tgt->client, di->tgt->port);
176 if (r < 0) { _ok=0; fprintf(stderr, "Cannot connect to %d:%d\n",di->tgtclient,di->tgtport); }
177 time=0;
178#endif
179}
180
181void AlsaOut::closeDev (void)
182{
183 if (!ok()) return;
184#ifdef HAVE_ALSA_SEQ
185 if (di->handle)
186 {
187 if (di->src)
188 {
189 snd_seq_delete_simple_port(di->handle,di->src->port);
190 delete di->src;
191 di->src=0;
192 }
193 if (di->tgt)
194 {
195 delete di->tgt;
196 di->tgt=0;
197 }
198 if (di->queue)
199 {
200 snd_seq_free_queue(di->handle, di->queue);
201 snd_seq_close(di->handle);
202 }
203 di->handle=0;
204 }
205
206#endif
207}
208
209void AlsaOut::initDev (void)
210{
211#ifdef HAVE_ALSA_SEQ
212 int chn;
213 if (!ok()) return;
214 uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7};
215 sysex(gm_reset, sizeof(gm_reset));
216 for (chn=0;chn<16;chn++)
217 {
218 chnmute[chn]=0;
219 if (chn!=9) chnPatchChange(chn,0);
220 chnPressure(chn,64);
221 chnPitchBender(chn, 0x00, 0x40);
222 chnController(chn, CTL_MAIN_VOLUME,110*volumepercentage);
223 chnController(chn, CTL_EXT_EFF_DEPTH, 0);
224 chnController(chn, CTL_CHORUS_DEPTH, 0);
225 chnController(chn, 0x4a, 127);
226 }
227#endif
228}
229
230#ifdef HAVE_ALSA_SEQ
231void AlsaOut::eventInit(snd_seq_event_t *ev)
232{
233 snd_seq_ev_clear(ev);
234 snd_seq_real_time_t tmp;
235 tmp.tv_sec=(time)/1000;
236 tmp.tv_nsec=(time%1000)*1000000;
237// printf("time : %d %d %d\n",(int)time,(int)tmp.tv_sec, (int)tmp.tv_nsec);
238 if (!di->src) { fprintf(stderr,"AlsaOut::eventInit : no source\n"); return; }
239 ev->source = *di->src;
240 if (!di->tgt) { fprintf(stderr,"AlsaOut::eventInit : no target\n"); return; }
241 ev->dest = *di->tgt;
242
243 snd_seq_ev_schedule_real(ev, di->queue, 0, &tmp);
244}
245
246void AlsaOut::eventSend(snd_seq_event_t *ev)
247{
248 /*int err = */ snd_seq_event_output(di->handle, ev);
249/* if (err < 0)
250 return;
251*/
252//#ifndef SND_SEQ_IOCTL_GET_CLIENT_POOL
253 /*
254 * If this is not defined then block mode writes will not be
255 * working correctly. Therefore loop until all events are flushed
256 * out.
257 */
258/* err = 0;
259 do {
260 err = snd_seq_flush_output(di->handle);
261 if (err > 0)
262 usleep(2000);
263 } while (err > 0);
264
265#endif
266
267 return ;
268*/
269}
270
271void AlsaOut::timerEventSend(int type)
272{
273 snd_seq_event_t ev;
274
275 ev.queue = di->queue;
276 ev.dest.client = SND_SEQ_CLIENT_SYSTEM;
277 ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
278
279 ev.data.queue.queue = di->queue;
280
281 ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL;
282 ev.time.time.tv_sec = 0;
283 ev.time.time.tv_nsec = 0;
284
285 ev.type = type;
286
287 snd_seq_event_output(di->handle, &ev);
288 snd_seq_flush_output(di->handle);
289}
290
291#endif // HAVE_ALSA_SEQ
292
293#ifndef HAVE_ALSA_SEQ
294void AlsaOut::noteOn (uchar , uchar , uchar )
295{
296#else
297void AlsaOut::noteOn (uchar chn, uchar note, uchar vel)
298{
299 if (vel==0)
300 {
301 noteOff(chn,note,vel);
302 }
303 else
304 {
305 eventInit(di->ev);
306 snd_seq_ev_set_noteon(di->ev,map->channel(chn), map->key(chn,chnpatch[chn],note), vel);
307 eventSend(di->ev);
308 }
309#endif
310#ifdef MIDIOUTDEBUG
311 printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
312#endif
313}
314
315#ifndef HAVE_ALSA_SEQ
316void AlsaOut::noteOff (uchar , uchar , uchar )
317{
318#else
319void AlsaOut::noteOff (uchar chn, uchar note, uchar vel)
320{
321 eventInit(di->ev);
322 snd_seq_ev_set_noteoff(di->ev,map->channel(chn), map->key(chn,chnpatch[chn],note), vel);
323 eventSend(di->ev);
324#endif
325#ifdef MIDIOUTDEBUG
326 printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
327#endif
328}
329
330#ifndef HAVE_ALSA_SEQ
331void AlsaOut::keyPressure (uchar , uchar , uchar )
332{
333#else
334void AlsaOut::keyPressure (uchar chn, uchar note, uchar vel)
335{
336 eventInit(di->ev);
337 snd_seq_ev_set_keypress(di->ev,map->channel(chn), map->key(chn,chnpatch[chn],note), vel);
338 eventSend(di->ev);
339#endif
340}
341
342#ifndef HAVE_ALSA_SEQ
343void AlsaOut::chnPatchChange (uchar , uchar )
344{
345#else
346void AlsaOut::chnPatchChange (uchar chn, uchar patch)
347{
348#ifdef MIDIOUTDEBUG
349 printfdebug("PATCHCHANGE [%d->%d] %d -> %d\n",
350 chn,map->channel(chn),patch,map->patch(chn,patch));
351#endif
352 eventInit(di->ev);
353 snd_seq_ev_set_pgmchange(di->ev,map->channel(chn), map->patch(chn,patch));
354 eventSend(di->ev);
355 chnpatch[chn]=patch;
356#endif
357}
358
359#ifndef HAVE_ALSA_SEQ
360void AlsaOut::chnPressure (uchar , uchar )
361{
362#else
363void AlsaOut::chnPressure (uchar chn, uchar vel)
364{
365 eventInit(di->ev);
366 snd_seq_ev_set_chanpress(di->ev,map->channel(chn), vel);
367 eventSend(di->ev);
368
369 chnpressure[chn]=vel;
370#endif
371}
372
373#ifndef HAVE_ALSA_SEQ
374void AlsaOut::chnPitchBender(uchar ,uchar , uchar )
375{
376#else
377void AlsaOut::chnPitchBender(uchar chn,uchar lsb, uchar msb)
378{
379 map->pitchBender(chn,lsb,msb);
380 chnbender[chn]=((short)msb<<7) | (lsb & 0x7F);
381 chnbender[chn]=chnbender[chn]-0x2000;
382
383 eventInit(di->ev);
384 snd_seq_ev_set_pitchbend(di->ev,map->channel(chn), chnbender[chn]);
385 eventSend(di->ev);
386#endif
387}
388
389#ifndef HAVE_ALSA_SEQ
390void AlsaOut::chnController (uchar , uchar , uchar )
391{
392#else
393void AlsaOut::chnController (uchar chn, uchar ctl, uchar v)
394{
395 map->controller(chn,ctl,v);
396 if ((ctl==11)||(ctl==7))
397 {
398 v=(v*volumepercentage)/100;
399 if (v>127) v=127;
400 }
401
402 eventInit(di->ev);
403 snd_seq_ev_set_controller(di->ev,map->channel(chn), ctl, v);
404 eventSend(di->ev);
405
406 chncontroller[chn][ctl]=v;
407#endif
408}
409
410#ifndef HAVE_ALSA_SEQ
411void AlsaOut::sysex(uchar *, ulong )
412{
413#else
414void AlsaOut::sysex(uchar *data, ulong size)
415{
416 eventInit(di->ev);
417 snd_seq_ev_set_sysex(di->ev, size, data);
418 eventSend(di->ev);
419#endif
420
421#ifdef MIDIOUTDEBUG
422 printfdebug("sysex\n");
423#endif
424}
425
426#ifndef HAVE_ALSA_SEQ
427void AlsaOut::channelSilence (uchar )
428{
429#else
430void AlsaOut::channelSilence (uchar chn)
431{
432 uchar i;
433 for ( i=0; i<127; i++)
434 {
435 noteOff(chn,i,0);
436 }
437#endif
438}
439
440#ifndef HAVE_ALSA_SEQ
441void AlsaOut::channelMute(uchar , int )
442{
443#else
444void AlsaOut::channelMute(uchar chn, int a)
445{
446 if (a==1)
447 {
448 chnmute[chn]=a;
449 channelSilence(chn);
450 }
451 else if (a==0)
452 {
453 chnmute[chn]=a;
454 }
455 /* else ignore the call to this procedure */
456#endif
457}
458
459void AlsaOut::seqbuf_dump (void)
460{
461 printf("You shouldn't be here.\n");
462}
463
464void AlsaOut::seqbuf_clean(void)
465{
466 printf("You shouldn't be here neither.\n");
467}
468
469void AlsaOut::wait(double ticks)
470{
471// SEQ_WAIT_TIME(((int)(ticks/convertrate)));
472 time=static_cast<long int>(ticks);
473
474#ifdef MIDIOUTDEBUG
475 printfdebug("Wait >\t ticks: %g\n",ticks);
476#endif
477}
478
479#ifndef HAVE_ALSA_SEQ
480void AlsaOut::tmrSetTempo(int )
481{
482#else
483void AlsaOut::tmrSetTempo(int v)
484{
485 eventInit(di->ev);
486 di->ev->type = SND_SEQ_EVENT_TEMPO;
487 snd_seq_ev_set_direct(di->ev);
488 di->ev->data.queue.queue = di->queue;
489 di->ev->data.queue.param.value = v;
490 di->ev->dest.client = SND_SEQ_CLIENT_SYSTEM;
491 di->ev->dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
492 snd_seq_event_output_direct(di->handle, di->ev);
493#ifdef MIDIOUTDEBUG
494 printfdebug("SETTEMPO >\t tempo: %d\n",v);
495#endif
496#endif
497}
498
499#ifndef HAVE_ALSA_SEQ
500void AlsaOut::sync(int )
501{
502#else
503void AlsaOut::sync(int i)
504{
505 if (i==1)
506 {
507 snd_seq_flush_output(di->handle);
508 }
509
510 if (di->timerStarted && di->src)
511 {
512 eventInit(di->ev);
513 di->ev->dest = *di->src;
514 eventSend(di->ev);
515 snd_seq_flush_output(di->handle);
516 snd_seq_event_input(di->handle,&di->ev);
517 }
518
519#endif
520}
521
522#ifndef HAVE_ALSA_SEQ
523void AlsaOut::tmrStart(int )
524{
525#else
526void AlsaOut::tmrStart(int tpcn)
527{
528 int ret;
529 di->timerStarted=true;
530 di->tPCN=tpcn;
531
532#ifdef HAVE_LIBASOUND2
533 snd_seq_queue_tempo_t *queuetempo;
534 snd_seq_queue_tempo_alloca(&queuetempo);
535 snd_seq_queue_tempo_set_ppq(queuetempo, tpcn);
536 snd_seq_queue_tempo_set_tempo(queuetempo, 60*1000000/120);
537 ret = snd_seq_set_queue_tempo(di->handle, di->queue, queuetempo);
538#else
539 snd_seq_queue_tempo_t queuetempo;
540 memset(&queuetempo, 0, sizeof(queuetempo));
541 queuetempo.queue = di->queue;
542 queuetempo.ppq = tpcn;
543 queuetempo.tempo = 60*1000000/120;
544 ret = snd_seq_set_queue_tempo(di->handle, di->queue, &queuetempo);
545#endif
546
547 timerEventSend(SND_SEQ_EVENT_START);
548 snd_seq_start_queue(di->handle,di->queue,NULL);
549#endif
550}
551
552void AlsaOut::tmrStop(void)
553{
554#ifdef HAVE_ALSA_SEQ
555 di->timerStarted=false;
556 timerEventSend(SND_SEQ_EVENT_STOP);
557#endif
558}
559
560void AlsaOut::tmrContinue(void)
561{
562}
563
564const char * AlsaOut::deviceName(void) const
565{
566#ifdef HAVE_ALSA_SEQ
567 return di->tgtname;
568#else
569 return 0L;
570#endif
571}
AlsaOut::channelSilence
virtual void channelSilence(uchar chn)
Mutes all notes being played on a given channel.
Definition: alsaout.cpp:427
AlsaOut::chnPatchChange
virtual void chnPatchChange(uchar chn, uchar patch)
See DeviceManager::chnPatchChange()
Definition: alsaout.cpp:343
AlsaOut::AlsaOut
AlsaOut(int d, int client=64, int port=0, const char *cname="", const char *pname="")
Constructor.
Definition: alsaout.cpp:111
AlsaOut::deviceName
virtual const char * deviceName(void) const
Returns the name and type of this MIDI device.
Definition: alsaout.cpp:564
AlsaOut::channelMute
virtual void channelMute(uchar chn, int b)
Mute or "unmute" a given channel .
Definition: alsaout.cpp:441
AlsaOut::~AlsaOut
virtual ~AlsaOut()
Destructor.
Definition: alsaout.cpp:126
AlsaOut::sysex
virtual void sysex(uchar *data, ulong size)
See DeviceManager::sysex()
Definition: alsaout.cpp:411
AlsaOut::chnPressure
virtual void chnPressure(uchar chn, uchar vel)
See DeviceManager::chnPressure()
Definition: alsaout.cpp:360
AlsaOut::closeDev
virtual void closeDev()
Closes the device.
Definition: alsaout.cpp:181
AlsaOut::openDev
virtual void openDev(int sqfd)
Opens the device.
Definition: alsaout.cpp:132
AlsaOut::initDev
virtual void initDev()
Initializes the device sending generic standard midi events and controllers, such as changing the pat...
Definition: alsaout.cpp:209
AlsaOut::keyPressure
virtual void keyPressure(uchar chn, uchar note, uchar vel)
See DeviceManager::keyPressure()
Definition: alsaout.cpp:331
AlsaOut::chnController
virtual void chnController(uchar chn, uchar ctl, uchar v)
See DeviceManager::chnController()
Definition: alsaout.cpp:390
AlsaOut::ok
int ok(void)
Returns true if everything's ok and false if there has been any problem.
Definition: alsaout.h:209
AlsaOut::noteOff
virtual void noteOff(uchar chn, uchar note, uchar vel)
See DeviceManager::noteOff()
Definition: alsaout.cpp:316
AlsaOut::noteOn
virtual void noteOn(uchar chn, uchar note, uchar vel)
See DeviceManager::noteOn()
Definition: alsaout.cpp:294
AlsaOut::chnPitchBender
virtual void chnPitchBender(uchar chn, uchar lsb, uchar msb)
See DeviceManager::chnPitchBender()
Definition: alsaout.cpp:374
MidiMapper::controller
void controller(uchar chn, uchar &ctl, uchar &v)
Returns the value which a given controller and its value should be mapped to when played on channel c...
Definition: midimapper.cpp:453
MidiMapper::channel
uchar channel(uchar chn)
Returns the channel which chn should be mapped to.
Definition: midimapper.h:177
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
MidiMapper::key
uchar key(uchar chn, uchar pgm, uchar note)
Returns the key that key note playing a pgm patch on channel chn should be mapped to.
Definition: midimapper.cpp:423
MidiMapper::pitchBender
void pitchBender(uchar chn, uchar &lsb, uchar &msb)
Returns the value which the pitch bender on channel chn should be mapped to.
Definition: midimapper.cpp:437
MidiOut
External MIDI port output class .
Definition: midiout.h:52

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.