42#ifdef HAVE_ALSA_ASOUNDLIB_H
43# include <alsa/asoundlib.h>
44#elif defined(HAVE_SYS_ASOUNDLIB_H)
45# include <sys/asoundlib.h>
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>
59class 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;
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++)
231void 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);
246void AlsaOut::eventSend(snd_seq_event_t *ev)
248 snd_seq_event_output(di->handle, ev);
271void 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);
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);
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);
337 snd_seq_ev_set_keypress(di->ev,map->
channel(chn), map->
key(chn,chnpatch[chn],note), vel);
349 printfdebug(
"PATCHCHANGE [%d->%d] %d -> %d\n",
353 snd_seq_ev_set_pgmchange(di->ev,map->
channel(chn), map->
patch(chn,patch));
366 snd_seq_ev_set_chanpress(di->ev,map->
channel(chn), vel);
369 chnpressure[chn]=vel;
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]);
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;
417 snd_seq_ev_set_sysex(di->ev, size, data);
422 printfdebug(
"sysex\n");
433 for ( i=0; i<127; i++)
459void AlsaOut::seqbuf_dump (
void)
461 printf(
"You shouldn't be here.\n");
464void AlsaOut::seqbuf_clean(
void)
466 printf(
"You shouldn't be here neither.\n");
469void AlsaOut::wait(
double ticks)
472 time=
static_cast<long int>(ticks);
475 printfdebug(
"Wait >\t ticks: %g\n",ticks);
480void AlsaOut::tmrSetTempo(
int )
483void 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);
500void AlsaOut::sync(
int )
503void AlsaOut::sync(
int i)
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);
523void AlsaOut::tmrStart(
int )
526void 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);
552void AlsaOut::tmrStop(
void)
555 di->timerStarted=
false;
556 timerEventSend(SND_SEQ_EVENT_STOP);
560void AlsaOut::tmrContinue(
void)
virtual void channelSilence(uchar chn)
Mutes all notes being played on a given channel.
virtual void chnPatchChange(uchar chn, uchar patch)
See DeviceManager::chnPatchChange()
AlsaOut(int d, int client=64, int port=0, const char *cname="", const char *pname="")
Constructor.
virtual const char * deviceName(void) const
Returns the name and type of this MIDI device.
virtual void channelMute(uchar chn, int b)
Mute or "unmute" a given channel .
virtual ~AlsaOut()
Destructor.
virtual void sysex(uchar *data, ulong size)
See DeviceManager::sysex()
virtual void chnPressure(uchar chn, uchar vel)
See DeviceManager::chnPressure()
virtual void closeDev()
Closes the device.
virtual void openDev(int sqfd)
Opens the device.
virtual void initDev()
Initializes the device sending generic standard midi events and controllers, such as changing the pat...
virtual void keyPressure(uchar chn, uchar note, uchar vel)
See DeviceManager::keyPressure()
virtual void chnController(uchar chn, uchar ctl, uchar v)
See DeviceManager::chnController()
int ok(void)
Returns true if everything's ok and false if there has been any problem.
virtual void noteOff(uchar chn, uchar note, uchar vel)
See DeviceManager::noteOff()
virtual void noteOn(uchar chn, uchar note, uchar vel)
See DeviceManager::noteOn()
virtual void chnPitchBender(uchar chn, uchar lsb, uchar msb)
See DeviceManager::chnPitchBender()
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...
uchar channel(uchar chn)
Returns the channel which chn should be mapped to.
uchar patch(uchar chn, uchar pgm)
Returns the patch which pgm used on channel chn should be mapped to.
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.
void pitchBender(uchar chn, uchar &lsb, uchar &msb)
Returns the value which the pitch bender on channel chn should be mapped to.
External MIDI port output class .