34 #include <sys/param.h>
42 #ifdef HAVE_ALSA_ASOUNDLIB_H
43 # include <alsa/asoundlib.h>
44 #elif defined(HAVE_SYS_ASOUNDLIB_H)
45 # include <sys/asoundlib.h>
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>
59 class AlsaOut::AlsaOutPrivate
63 AlsaOutPrivate(
int _client,
int _port,
const char *cname,
const char *pname)
71 tgtname=
new char[strlen(cname)+strlen(pname)+3];
72 strcpy(tgtname, cname);
74 strcat(tgtname, pname);
75 ev=
new snd_seq_event_t;
79 AlsaOutPrivate(
int,
int,
const char *,
const char *)
113 di =
new AlsaOutPrivate( _client, _port, cname, pname);
115 devicetype=KMID_ALSA;
118 volumepercentage=100;
134 #ifndef HAVE_ALSA_SEQ
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));
142 if (snd_seq_open(&di->handle, SND_SEQ_OPEN) < 0)
143 fprintf(stderr,
"Couldn't open sequencer: %s", snd_strerror(errno));
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;
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);
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);
172 di->src->port = port;
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); }
189 snd_seq_delete_simple_port(di->handle,di->src->port);
200 snd_seq_free_queue(di->handle, di->queue);
201 snd_seq_close(di->handle);
214 uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7};
215 sysex(gm_reset,
sizeof(gm_reset));
216 for (chn=0;chn<16;chn++)
231 void AlsaOut::eventInit(snd_seq_event_t *ev)
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;
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; }
243 snd_seq_ev_schedule_real(ev, di->queue, 0, &tmp);
246 void AlsaOut::eventSend(snd_seq_event_t *ev)
248 snd_seq_event_output(di->handle, ev);
271 void AlsaOut::timerEventSend(
int type)
275 ev.queue = di->queue;
276 ev.dest.client = SND_SEQ_CLIENT_SYSTEM;
277 ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
279 ev.data.queue.queue = di->queue;
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;
287 snd_seq_event_output(di->handle, &ev);
288 snd_seq_flush_output(di->handle);
291 #endif // HAVE_ALSA_SEQ
293 #ifndef HAVE_ALSA_SEQ
306 snd_seq_ev_set_noteon(di->ev,map->
channel(chn), map->
key(chn,chnpatch[chn],note), vel);
311 printfdebug(
"Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
315 #ifndef HAVE_ALSA_SEQ
322 snd_seq_ev_set_noteoff(di->ev,map->
channel(chn), map->
key(chn,chnpatch[chn],note), vel);
326 printfdebug(
"Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
330 #ifndef HAVE_ALSA_SEQ
337 snd_seq_ev_set_keypress(di->ev,map->
channel(chn), map->
key(chn,chnpatch[chn],note), vel);
342 #ifndef HAVE_ALSA_SEQ
349 printfdebug(
"PATCHCHANGE [%d->%d] %d -> %d\n",
353 snd_seq_ev_set_pgmchange(di->ev,map->
channel(chn), map->
patch(chn,patch));
359 #ifndef HAVE_ALSA_SEQ
366 snd_seq_ev_set_chanpress(di->ev,map->
channel(chn), vel);
369 chnpressure[chn]=vel;
373 #ifndef HAVE_ALSA_SEQ
380 chnbender[chn]=((short)msb<<7) | (lsb & 0x7F);
381 chnbender[chn]=chnbender[chn]-0x2000;
384 snd_seq_ev_set_pitchbend(di->ev,map->
channel(chn), chnbender[chn]);
389 #ifndef HAVE_ALSA_SEQ
396 if ((ctl==11)||(ctl==7))
398 v=(v*volumepercentage)/100;
403 snd_seq_ev_set_controller(di->ev,map->
channel(chn), ctl, v);
406 chncontroller[chn][ctl]=v;
410 #ifndef HAVE_ALSA_SEQ
417 snd_seq_ev_set_sysex(di->ev, size, data);
422 printfdebug(
"sysex\n");
426 #ifndef HAVE_ALSA_SEQ
433 for ( i=0; i<127; i++)
440 #ifndef HAVE_ALSA_SEQ
459 void AlsaOut::seqbuf_dump (
void)
461 printf(
"You shouldn't be here.\n");
464 void AlsaOut::seqbuf_clean(
void)
466 printf(
"You shouldn't be here neither.\n");
469 void AlsaOut::wait(
double ticks)
472 time=
static_cast<long int>(ticks);
475 printfdebug(
"Wait >\t ticks: %g\n",ticks);
479 #ifndef HAVE_ALSA_SEQ
480 void AlsaOut::tmrSetTempo(
int )
483 void AlsaOut::tmrSetTempo(
int v)
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);
494 printfdebug(
"SETTEMPO >\t tempo: %d\n",v);
499 #ifndef HAVE_ALSA_SEQ
507 snd_seq_flush_output(di->handle);
510 if (di->timerStarted && di->src)
513 di->ev->dest = *di->src;
515 snd_seq_flush_output(di->handle);
516 snd_seq_event_input(di->handle,&di->ev);
522 #ifndef HAVE_ALSA_SEQ
523 void AlsaOut::tmrStart(
int )
526 void AlsaOut::tmrStart(
int tpcn)
529 di->timerStarted=
true;
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);
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);
547 timerEventSend(SND_SEQ_EVENT_START);
548 snd_seq_start_queue(di->handle,di->queue,NULL);
552 void AlsaOut::tmrStop(
void)
555 di->timerStarted=
false;
556 timerEventSend(SND_SEQ_EVENT_STOP);
560 void AlsaOut::tmrContinue(
void)