00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
#include "alsaout.h"
00027
#include <unistd.h>
00028
#include <fcntl.h>
00029
#include <stdio.h>
00030
#include "sndcard.h"
00031
#include <errno.h>
00032
#include <string.h>
00033
#include <stdlib.h>
00034
#include <sys/param.h>
00035
#include "midispec.h"
00036
00037
00038
#ifdef HAVE_CONFIG_H
00039
#include <config.h>
00040
#endif
00041
00042
#ifdef HAVE_ALSA_ASOUNDLIB_H
00043
# include <alsa/asoundlib.h>
00044
#elif defined(HAVE_SYS_ASOUNDLIB_H)
00045
# include <sys/asoundlib.h>
00046
#endif
00047
00048
#ifdef HAVE_LIBASOUND2
00049
# define HAVE_ALSA_SEQ 1
00050
# define snd_seq_flush_output(x) snd_seq_drain_output(x)
00051
#elif defined(HAVE_LIBASOUND)
00052
# define HAVE_ALSA_SEQ 1
00053
# include <linux/asequencer.h>
00054
#endif
00055
00056
00057 SEQ_USE_EXTBUF();
00058
00059
class AlsaOut::AlsaOutPrivate
00060 {
00061
public:
00062
#ifdef HAVE_ALSA_SEQ
00063
AlsaOutPrivate(
int _client,
int _port,
const char *cname,
const char *pname)
00064 {
00065 handle=0L;
00066 src=tgt=0L;
00067 queue=0;
00068 tPCN=1;
00069 tgtclient=_client;
00070 tgtport=_port;
00071 tgtname=
new char[strlen(cname)+strlen(pname)+3];
00072 strcpy(tgtname, cname);
00073 strcat(tgtname,
" ");
00074 strcat(tgtname, pname);
00075 ev=
new snd_seq_event_t;
00076 timerStarted=
false;
00077 }
00078
#else
00079
AlsaOutPrivate(
int,
int,
const char *,
const char *)
00080 {
00081 }
00082
#endif
00083
00084 ~AlsaOutPrivate()
00085 {
00086
#ifdef HAVE_ALSA_SEQ
00087
delete ev;
00088
delete tgtname;
00089
#endif
00090
}
00091
00092
#ifdef HAVE_ALSA_SEQ
00093
snd_seq_t *handle;
00094
int client;
00095
int queue;
00096 snd_seq_addr_t *src;
00097 snd_seq_addr_t *tgt;
00098
00099 snd_seq_event_t *ev;
00100
int tPCN;
00101
00102
int tgtclient;
00103
int tgtport;
00104
char *tgtname;
00105
00106
bool timerStarted;
00107
00108
#endif
00109
};
00110
00111 AlsaOut::AlsaOut(
int d,
int _client,
int _port,
const char *cname,
const char *pname) :
MidiOut (d)
00112 {
00113 di =
new AlsaOutPrivate( _client, _port, cname, pname);
00114 seqfd = 0;
00115 devicetype=KMID_ALSA;
00116 device= d;
00117
00118 volumepercentage=100;
00119
#ifdef HAVE_ALSA_SEQ
00120
00121
#endif
00122
00123 _ok=1;
00124 }
00125
00126 AlsaOut::~AlsaOut()
00127 {
00128
closeDev();
00129
delete di;
00130 }
00131
00132 void AlsaOut::openDev (
int)
00133 {
00134
#ifndef HAVE_ALSA_SEQ
00135
return;
00136
#else
00137
_ok=1;
00138
#ifdef HAVE_LIBASOUND2
00139
if (snd_seq_open(&di->handle,
"hw", SND_SEQ_OPEN_DUPLEX, 0) < 0)
00140 fprintf(stderr,
"Couldn't open sequencer: %s", snd_strerror(errno));
00141
#else
00142
if (snd_seq_open(&di->handle, SND_SEQ_OPEN) < 0)
00143 fprintf(stderr,
"Couldn't open sequencer: %s", snd_strerror(errno));
00144
#endif
00145
00146 di->queue = snd_seq_alloc_queue(di->handle);
00147
if (di->queue < 0) {fprintf(stderr,
"Couldn't allocate queue");
return; };
00148 di->client = snd_seq_client_id(di->handle);
00149
if (di->client < 0) {fprintf(stderr,
"Couldn't get client id");
return; };
00150 di->tgt =
new snd_seq_addr_t;
00151 di->tgt->client=di->tgtclient;
00152 di->tgt->port=di->tgtport;
00153
00154 di->src =
new snd_seq_addr_t;
00155 di->src->client = di->client;
00156
int port = snd_seq_create_simple_port(di->handle, NULL,
00157 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE
00158 | SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC);
00159
if ( port < 0 )
00160 {
00161
delete di->src;
00162
delete di->tgt;
00163 di->src=0;
00164 di->tgt=0;
00165 _ok=0;
00166 time=0;
00167 snd_seq_free_queue(di->handle, di->queue);
00168 snd_seq_close(di->handle);
00169 fprintf(stderr,
"Cannot connect to %d:%d\n",di->tgtclient,di->tgtport);
00170
return;
00171 }
00172 di->src->port = port;
00173
00174
00175
int r=snd_seq_connect_to(di->handle, di->src->port, di->tgt->client, di->tgt->port);
00176
if (r < 0) { _ok=0; fprintf(stderr,
"Cannot connect to %d:%d\n",di->tgtclient,di->tgtport); }
00177 time=0;
00178
#endif
00179
}
00180
00181 void AlsaOut::closeDev (
void)
00182 {
00183
if (!
ok())
return;
00184
#ifdef HAVE_ALSA_SEQ
00185
if (di->handle)
00186 {
00187
if (di->src)
00188 {
00189 snd_seq_delete_simple_port(di->handle,di->src->port);
00190
delete di->src;
00191 di->src=0;
00192 }
00193
if (di->tgt)
00194 {
00195
delete di->tgt;
00196 di->tgt=0;
00197 }
00198
if (di->queue)
00199 {
00200 snd_seq_free_queue(di->handle, di->queue);
00201 snd_seq_close(di->handle);
00202 }
00203 di->handle=0;
00204 }
00205
00206
#endif
00207
}
00208
00209 void AlsaOut::initDev (
void)
00210 {
00211
#ifdef HAVE_ALSA_SEQ
00212
int chn;
00213
if (!
ok())
return;
00214 uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7};
00215
sysex(gm_reset,
sizeof(gm_reset));
00216
for (chn=0;chn<16;chn++)
00217 {
00218 chnmute[chn]=0;
00219
if (chn!=9)
chnPatchChange(chn,0);
00220
chnPressure(chn,64);
00221
chnPitchBender(chn, 0x00, 0x40);
00222
chnController(chn, CTL_MAIN_VOLUME,110*volumepercentage);
00223
chnController(chn, CTL_EXT_EFF_DEPTH, 0);
00224
chnController(chn, CTL_CHORUS_DEPTH, 0);
00225
chnController(chn, 0x4a, 127);
00226 }
00227
#endif
00228
}
00229
00230
#ifdef HAVE_ALSA_SEQ
00231
void AlsaOut::eventInit(snd_seq_event_t *ev)
00232 {
00233 snd_seq_ev_clear(ev);
00234 snd_seq_real_time_t tmp;
00235 tmp.tv_sec=(time)/1000;
00236 tmp.tv_nsec=(time%1000)*1000000;
00237
00238
if (!di->src) { fprintf(stderr,
"AlsaOut::eventInit : no source\n");
return; }
00239 ev->source = *di->src;
00240
if (!di->tgt) { fprintf(stderr,
"AlsaOut::eventInit : no target\n");
return; }
00241 ev->dest = *di->tgt;
00242
00243 snd_seq_ev_schedule_real(ev, di->queue, 0, &tmp);
00244 }
00245
00246
void AlsaOut::eventSend(snd_seq_event_t *ev)
00247 {
00248 snd_seq_event_output(di->handle, ev);
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 }
00270
00271
void AlsaOut::timerEventSend(
int type)
00272 {
00273 snd_seq_event_t ev;
00274
00275 ev.queue = di->queue;
00276 ev.dest.client = SND_SEQ_CLIENT_SYSTEM;
00277 ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
00278
00279 ev.data.queue.queue = di->queue;
00280
00281 ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL;
00282 ev.time.time.tv_sec = 0;
00283 ev.time.time.tv_nsec = 0;
00284
00285 ev.type = type;
00286
00287 snd_seq_event_output(di->handle, &ev);
00288 snd_seq_flush_output(di->handle);
00289 }
00290
00291
#endif // HAVE_ALSA_SEQ
00292
00293
#ifndef HAVE_ALSA_SEQ
00294 void AlsaOut::noteOn (uchar , uchar , uchar )
00295 {
00296
#else
00297
void AlsaOut::noteOn (uchar chn, uchar note, uchar vel)
00298 {
00299
if (vel==0)
00300 {
00301
noteOff(chn,note,vel);
00302 }
00303
else
00304 {
00305 eventInit(di->ev);
00306 snd_seq_ev_set_noteon(di->ev,map->
channel(chn), map->
key(chn,chnpatch[chn],note), vel);
00307 eventSend(di->ev);
00308 }
00309
#endif
00310
#ifdef MIDIOUTDEBUG
00311
printfdebug(
"Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
00312
#endif
00313
}
00314
00315
#ifndef HAVE_ALSA_SEQ
00316 void AlsaOut::noteOff (uchar , uchar , uchar )
00317 {
00318
#else
00319
void AlsaOut::noteOff (uchar chn, uchar note, uchar vel)
00320 {
00321 eventInit(di->ev);
00322 snd_seq_ev_set_noteoff(di->ev,map->
channel(chn), map->
key(chn,chnpatch[chn],note), vel);
00323 eventSend(di->ev);
00324
#endif
00325
#ifdef MIDIOUTDEBUG
00326
printfdebug(
"Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel);
00327
#endif
00328
}
00329
00330
#ifndef HAVE_ALSA_SEQ
00331 void AlsaOut::keyPressure (uchar , uchar , uchar )
00332 {
00333
#else
00334
void AlsaOut::keyPressure (uchar chn, uchar note, uchar vel)
00335 {
00336 eventInit(di->ev);
00337 snd_seq_ev_set_keypress(di->ev,map->
channel(chn), map->
key(chn,chnpatch[chn],note), vel);
00338 eventSend(di->ev);
00339
#endif
00340
}
00341
00342
#ifndef HAVE_ALSA_SEQ
00343 void AlsaOut::chnPatchChange (uchar , uchar )
00344 {
00345
#else
00346
void AlsaOut::chnPatchChange (uchar chn, uchar patch)
00347 {
00348
#ifdef MIDIOUTDEBUG
00349
printfdebug(
"PATCHCHANGE [%d->%d] %d -> %d\n",
00350 chn,map->
channel(chn),patch,map->
patch(chn,patch));
00351
#endif
00352
eventInit(di->ev);
00353 snd_seq_ev_set_pgmchange(di->ev,map->
channel(chn), map->
patch(chn,patch));
00354 eventSend(di->ev);
00355 chnpatch[chn]=patch;
00356
#endif
00357
}
00358
00359
#ifndef HAVE_ALSA_SEQ
00360 void AlsaOut::chnPressure (uchar , uchar )
00361 {
00362
#else
00363
void AlsaOut::chnPressure (uchar chn, uchar vel)
00364 {
00365 eventInit(di->ev);
00366 snd_seq_ev_set_chanpress(di->ev,map->
channel(chn), vel);
00367 eventSend(di->ev);
00368
00369 chnpressure[chn]=vel;
00370
#endif
00371
}
00372
00373
#ifndef HAVE_ALSA_SEQ
00374 void AlsaOut::chnPitchBender(uchar ,uchar , uchar )
00375 {
00376
#else
00377
void AlsaOut::chnPitchBender(uchar chn,uchar lsb, uchar msb)
00378 {
00379 map->
pitchBender(chn,lsb,msb);
00380 chnbender[chn]=((
short)msb<<7) | (lsb & 0x7F);
00381 chnbender[chn]=chnbender[chn]-0x2000;
00382
00383 eventInit(di->ev);
00384 snd_seq_ev_set_pitchbend(di->ev,map->
channel(chn), chnbender[chn]);
00385 eventSend(di->ev);
00386
#endif
00387
}
00388
00389
#ifndef HAVE_ALSA_SEQ
00390 void AlsaOut::chnController (uchar , uchar , uchar )
00391 {
00392
#else
00393
void AlsaOut::chnController (uchar chn, uchar ctl, uchar v)
00394 {
00395 map->
controller(chn,ctl,v);
00396
if ((ctl==11)||(ctl==7))
00397 {
00398 v=(v*volumepercentage)/100;
00399
if (v>127) v=127;
00400 }
00401
00402 eventInit(di->ev);
00403 snd_seq_ev_set_controller(di->ev,map->
channel(chn), ctl, v);
00404 eventSend(di->ev);
00405
00406 chncontroller[chn][ctl]=v;
00407
#endif
00408
}
00409
00410
#ifndef HAVE_ALSA_SEQ
00411 void AlsaOut::sysex(uchar *, ulong )
00412 {
00413
#else
00414
void AlsaOut::sysex(uchar *data, ulong size)
00415 {
00416 eventInit(di->ev);
00417 snd_seq_ev_set_sysex(di->ev, size, data);
00418 eventSend(di->ev);
00419
#endif
00420
00421
#ifdef MIDIOUTDEBUG
00422
printfdebug(
"sysex\n");
00423
#endif
00424
}
00425
00426
#ifndef HAVE_ALSA_SEQ
00427 void AlsaOut::channelSilence (uchar )
00428 {
00429
#else
00430
void AlsaOut::channelSilence (uchar chn)
00431 {
00432 uchar i;
00433
for ( i=0; i<127; i++)
00434 {
00435
noteOff(chn,i,0);
00436 }
00437
#endif
00438
}
00439
00440
#ifndef HAVE_ALSA_SEQ
00441 void AlsaOut::channelMute(uchar ,
int )
00442 {
00443
#else
00444
void AlsaOut::channelMute(uchar chn,
int a)
00445 {
00446
if (a==1)
00447 {
00448 chnmute[chn]=a;
00449
channelSilence(chn);
00450 }
00451
else if (a==0)
00452 {
00453 chnmute[chn]=a;
00454 }
00455
00456
#endif
00457
}
00458
00459
void AlsaOut::seqbuf_dump (
void)
00460 {
00461 printf(
"You shouldn't be here.\n");
00462 }
00463
00464
void AlsaOut::seqbuf_clean(
void)
00465 {
00466 printf(
"You shouldn't be here neither.\n");
00467 }
00468
00469
void AlsaOut::wait(
double ticks)
00470 {
00471
00472 time=(
long int)ticks;
00473
00474
#ifdef MIDIOUTDEBUG
00475
printfdebug(
"Wait >\t ticks: %g\n",ticks);
00476
#endif
00477
}
00478
00479
#ifndef HAVE_ALSA_SEQ
00480
void AlsaOut::tmrSetTempo(
int )
00481 {
00482
#else
00483
void AlsaOut::tmrSetTempo(
int v)
00484 {
00485 eventInit(di->ev);
00486 di->ev->type = SND_SEQ_EVENT_TEMPO;
00487 snd_seq_ev_set_direct(di->ev);
00488 di->ev->data.queue.queue = di->queue;
00489 di->ev->data.queue.param.value = v;
00490 di->ev->dest.client = SND_SEQ_CLIENT_SYSTEM;
00491 di->ev->dest.port = SND_SEQ_PORT_SYSTEM_TIMER;
00492 snd_seq_event_output_direct(di->handle, di->ev);
00493
#ifdef MIDIOUTDEBUG
00494
printfdebug(
"SETTEMPO >\t tempo: %d\n",v);
00495
#endif
00496
#endif
00497
}
00498
00499
#ifndef HAVE_ALSA_SEQ
00500 void AlsaOut::sync(
int )
00501 {
00502
#else
00503
void AlsaOut::sync(
int i)
00504 {
00505
if (i==1)
00506 {
00507 snd_seq_flush_output(di->handle);
00508 }
00509
00510
if (di->timerStarted && di->src)
00511 {
00512 eventInit(di->ev);
00513 di->ev->dest = *di->src;
00514 eventSend(di->ev);
00515 snd_seq_flush_output(di->handle);
00516 snd_seq_event_input(di->handle,&di->ev);
00517 }
00518
00519
#endif
00520
}
00521
00522
#ifndef HAVE_ALSA_SEQ
00523
void AlsaOut::tmrStart(
int )
00524 {
00525
#else
00526
void AlsaOut::tmrStart(
int tpcn)
00527 {
00528
int ret;
00529 di->timerStarted=
true;
00530 di->tPCN=tpcn;
00531
00532
#ifdef HAVE_LIBASOUND2
00533
snd_seq_queue_tempo_t *queuetempo;
00534 snd_seq_queue_tempo_alloca(&queuetempo);
00535 snd_seq_queue_tempo_set_ppq(queuetempo, tpcn);
00536 snd_seq_queue_tempo_set_tempo(queuetempo, 60*1000000/120);
00537 ret = snd_seq_set_queue_tempo(di->handle, di->queue, queuetempo);
00538
#else
00539
snd_seq_queue_tempo_t queuetempo;
00540 memset(&queuetempo, 0,
sizeof(queuetempo));
00541 queuetempo.queue = di->queue;
00542 queuetempo.ppq = tpcn;
00543 queuetempo.tempo = 60*1000000/120;
00544 ret = snd_seq_set_queue_tempo(di->handle, di->queue, &queuetempo);
00545
#endif
00546
00547 timerEventSend(SND_SEQ_EVENT_START);
00548 snd_seq_start_queue(di->handle,di->queue,NULL);
00549
#endif
00550
}
00551
00552
void AlsaOut::tmrStop(
void)
00553 {
00554
#ifdef HAVE_ALSA_SEQ
00555
di->timerStarted=
false;
00556 timerEventSend(SND_SEQ_EVENT_STOP);
00557
#endif
00558
}
00559
00560
void AlsaOut::tmrContinue(
void)
00561 {
00562 }
00563
00564 const char *
AlsaOut::deviceName(
void)
const
00565
{
00566
#ifdef HAVE_ALSA_SEQ
00567
return di->tgtname;
00568
#else
00569
return 0L;
00570
#endif
00571
}