• 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 
57 SEQ_USE_EXTBUF();
58 
59 class AlsaOut::AlsaOutPrivate
60 {
61 public:
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 
111 AlsaOut::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 
126 AlsaOut::~AlsaOut()
127 {
128  closeDev();
129  delete di;
130 }
131 
132 void 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 
181 void 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 
209 void 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
231 void 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 
246 void 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 
271 void 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
294 void AlsaOut::noteOn (uchar , uchar , uchar )
295 {
296 #else
297 void 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
316 void AlsaOut::noteOff (uchar , uchar , uchar )
317 {
318 #else
319 void 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
331 void AlsaOut::keyPressure (uchar , uchar , uchar )
332 {
333 #else
334 void 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
343 void AlsaOut::chnPatchChange (uchar , uchar )
344 {
345 #else
346 void 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
360 void AlsaOut::chnPressure (uchar , uchar )
361 {
362 #else
363 void 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
374 void AlsaOut::chnPitchBender(uchar ,uchar , uchar )
375 {
376 #else
377 void 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
390 void AlsaOut::chnController (uchar , uchar , uchar )
391 {
392 #else
393 void 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
411 void AlsaOut::sysex(uchar *, ulong )
412 {
413 #else
414 void 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
427 void AlsaOut::channelSilence (uchar )
428 {
429 #else
430 void 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
441 void AlsaOut::channelMute(uchar , int )
442 {
443 #else
444 void 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 
459 void AlsaOut::seqbuf_dump (void)
460 {
461  printf("You shouldn't be here.\n");
462 }
463 
464 void AlsaOut::seqbuf_clean(void)
465 {
466  printf("You shouldn't be here neither.\n");
467 }
468 
469 void 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
480 void AlsaOut::tmrSetTempo(int )
481 {
482 #else
483 void 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
500 void AlsaOut::sync(int )
501 {
502 #else
503 void 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
523 void AlsaOut::tmrStart(int )
524 {
525 #else
526 void 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 
552 void AlsaOut::tmrStop(void)
553 {
554 #ifdef HAVE_ALSA_SEQ
555  di->timerStarted=false;
556  timerEventSend(SND_SEQ_EVENT_STOP);
557 #endif
558 }
559 
560 void AlsaOut::tmrContinue(void)
561 {
562 }
563 
564 const char * AlsaOut::deviceName(void) const
565 {
566 #ifdef HAVE_ALSA_SEQ
567  return di->tgtname;
568 #else
569  return 0L;
570 #endif
571 }
AlsaOut::AlsaOut
AlsaOut(int d, int client=64, int port=0, const char *cname="", const char *pname="")
Constructor.
Definition: alsaout.cpp:111
AlsaOut::chnPressure
virtual void chnPressure(uchar chn, uchar vel)
See DeviceManager::chnPressure()
Definition: alsaout.cpp:360
AlsaOut::channelMute
virtual void channelMute(uchar chn, int b)
Mute or "unmute" a given channel .
Definition: alsaout.cpp:441
AlsaOut::chnPatchChange
virtual void chnPatchChange(uchar chn, uchar patch)
See DeviceManager::chnPatchChange()
Definition: alsaout.cpp:343
AlsaOut::noteOff
virtual void noteOff(uchar chn, uchar note, uchar vel)
See DeviceManager::noteOff()
Definition: alsaout.cpp:316
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
AlsaOut::chnPitchBender
virtual void chnPitchBender(uchar chn, uchar lsb, uchar msb)
See DeviceManager::chnPitchBender()
Definition: alsaout.cpp:374
AlsaOut::deviceName
virtual const char * deviceName(void) const
Returns the name and type of this MIDI device.
Definition: alsaout.cpp:564
AlsaOut::closeDev
virtual void closeDev()
Closes the device.
Definition: alsaout.cpp:181
AlsaOut::noteOn
virtual void noteOn(uchar chn, uchar note, uchar vel)
See DeviceManager::noteOn()
Definition: alsaout.cpp:294
MidiMapper::channel
uchar channel(uchar chn)
Returns the channel which chn should be mapped to.
Definition: midimapper.h:177
AlsaOut::ok
int ok(void)
Returns true if everything's ok and false if there has been any problem.
Definition: alsaout.h:209
MidiOut
External MIDI port output class .
Definition: midiout.h:51
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
AlsaOut::sysex
virtual void sysex(uchar *data, ulong size)
See DeviceManager::sysex()
Definition: alsaout.cpp:411
AlsaOut::chnController
virtual void chnController(uchar chn, uchar ctl, uchar v)
See DeviceManager::chnController()
Definition: alsaout.cpp:390
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::channelSilence
virtual void channelSilence(uchar chn)
Mutes all notes being played on a given channel.
Definition: alsaout.cpp:427
AlsaOut::keyPressure
virtual void keyPressure(uchar chn, uchar note, uchar vel)
See DeviceManager::keyPressure()
Definition: alsaout.cpp:331
AlsaOut::~AlsaOut
virtual ~AlsaOut()
Destructor.
Definition: alsaout.cpp:126
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
AlsaOut::openDev
virtual void openDev(int sqfd)
Opens the device.
Definition: alsaout.cpp:132
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

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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for libtdemid by doxygen 1.8.8
This website is maintained by Timothy Pearson.