alsa-lib/test/seq-sender.c
Jaroslav Kysela 88e5e45151 Major change to sequencer API.
The sequencer API is totally recoded with the style of "encapsulation"
in other api.
The structure becomes opaque and accessed only via functions.

Other changes:
- There is no longer group in client and port info.
- snd_seq_query_subs_t is renamed to snd_seq_query_subscribe_t.
- snd_seq_delete_port takes only the port id argument instead of
  port_info structure.
- snd_seq_input/output_buffer_size are renamed
  as snd_seq_get_input/output_buffer_size.
  Similarly snd_seq_resize_input/output_buffer are renamed as
  snd_seq_set_input/output_buffer_size.
- snd_seq_get_named_queue is renamed to snd_seq_query_named_queue.
- Sync codes are removed temporarily from API.
- Subscription conditions are accessed via the corresponding functions.
  convert_time is named now as time_update.
- snd_seq_get/set_queue_owner are removed.
  Use snd_seq_get/set_queue_info instead.
- Instrument put/get/remove structure is unified as snd_instr_header_t.
2001-07-04 13:54:13 +00:00

269 lines
7.3 KiB
C

#ifdef USE_PCM // XXX not yet
/*
* PCM timer layer
*/
int pcard = 0;
int pdevice = 0;
int period_size = 1024;
void set_hwparams(snd_pcm_t *phandle)
{
int err;
snd_pcm_hw_params_t *params;
err = snd_output_stdio_attach(&log, stderr, 0);
if (err < 0) {
fprintf(stderr, "cannot attach output stdio\n");
exit(0);
}
snd_pcm_hw_params_alloca(&params);
err = snd_pcm_hw_params_any(phandle, params);
if (err < 0) {
fprintf(stderr, "Broken configuration for this PCM: no configurations available\n");
exit(0);
}
err = snd_pcm_hw_params_set_access(phandle, params,
SND_PCM_ACCESS_RW_INTERLEAVED);
if (err < 0) {
fprintf(stderr, "Access type not available\n");
exit(0);
}
err = snd_pcm_hw_params_set_format(phandle, params, SND_PCM_FORMAT_S16_LE);
if (err < 0) {
fprintf(stderr, "cannot set format\n");
exit(0);
}
err = snd_pcm_hw_params_set_channels(phandle, params, 2);
if (err < 0) {
fprintf(stderr, "cannot set channels 2\n");
exit(0);
}
err = snd_pcm_hw_params_set_rate_near(phandle, params, 44100, 0);
if (err < 0) {
fprintf(stderr, "cannot set rate\n");
exit(0);
}
err = snd_pcm_hw_params_set_period_size_near(phandle, params, period_size);
if (err < 0) {
fprintf(stderr, "cannot set period size\n");
exit(0);
}
err = snd_pcm_hw_params(phandle, params);
if (err < 0) {
fprintf(stderr, "Unable to install hw params:\n");
exit(0);
}
snd_pcm_hw_params_dump(params, log);
}
#endif
/*
* Simple event sender
*/
void event_sender_start_timer(snd_seq_t *handle, int client, int queue, snd_pcm_t *phandle)
{
int err;
#ifdef USE_PCM
if (phandle) {
snd_pcm_playback_info_t pinfo;
snd_seq_queue_timer_t qtimer;
if ((err = snd_pcm_playback_info(phandle, &pinfo)) < 0) {
fprintf(stderr, "Playback info error: %s\n", snd_strerror(err));
exit(0);
}
bzero(&qtimer, sizeof(qtimer));
qtimer.type = SND_SEQ_TIMER_MASTER;
/* note: last bit from subdevices specifies playback */
/* or capture direction for the timer specification */
qtimer.number = SND_TIMER_PCM(pcard, pdevice, pinfo.subdevice << 1);
if ((err = snd_seq_set_queue_timer(handle, queue, &qtimer)) < 0) {
fprintf(stderr, "Sequencer PCM timer setup failed: %s\n", snd_strerror(err));
exit(0);
}
}
#endif
if ((err = snd_seq_start_queue(handle, queue, NULL))<0)
fprintf(stderr, "Timer event output error: %s\n", snd_strerror(err));
snd_seq_drain_output(handle);
}
void event_sender_filter(snd_seq_t *handle)
{
int err;
if ((err = snd_seq_set_client_event_filter(handle, SND_SEQ_EVENT_ECHO)) < 0) {
fprintf(stderr, "Unable to set client info: %s\n", snd_strerror(err));
return;
}
}
void send_event(snd_seq_t *handle, int queue, int client, int port,
snd_seq_addr_t *dest, int *time)
{
int err;
snd_seq_event_t ev;
bzero(&ev, sizeof(ev));
ev.queue = queue;
ev.source.client = ev.dest.client = client;
ev.source.port = ev.dest.port = port;
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
ev.time.time.tv_sec = *time; (*time)++;
ev.type = SND_SEQ_EVENT_ECHO;
if ((err = snd_seq_event_output(handle, &ev))<0)
fprintf(stderr, "Event output error: %s\n", snd_strerror(err));
ev.dest = *dest;
ev.type = SND_SEQ_EVENT_PGMCHANGE;
ev.data.control.channel = 0;
ev.data.control.value = 16;
if ((err = snd_seq_event_output(handle, &ev))<0)
fprintf(stderr, "Event output error: %s\n", snd_strerror(err));
ev.type = SND_SEQ_EVENT_NOTE;
ev.data.note.channel = 0;
ev.data.note.note = 64 + (queue*2);
ev.data.note.velocity = 127;
ev.data.note.off_velocity = 127;
ev.data.note.duration = 500; /* 0.5sec */
if ((err = snd_seq_event_output(handle, &ev))<0)
fprintf(stderr, "Event output error: %s\n", snd_strerror(err));
if ((err = snd_seq_drain_output(handle))<0)
fprintf(stderr, "Event drain error: %s\n", snd_strerror(err));
}
void event_sender(snd_seq_t *handle, int argc, char *argv[])
{
snd_seq_event_t *ev;
snd_seq_port_info_t *pinfo;
snd_seq_port_subscribe_t *sub;
snd_seq_addr_t addr;
struct pollfd *pfds;
int client, port, queue, max, err, v1, v2, time = 0, pcm_flag = 0;
char *ptr;
snd_pcm_t *phandle = NULL;
if (argc < 1) {
fprintf(stderr, "Invalid destination...\n");
return;
}
if ((client = snd_seq_client_id(handle))<0) {
fprintf(stderr, "Cannot determine client number: %s\n", snd_strerror(client));
return;
}
printf("Client ID = %i\n", client);
if ((queue = snd_seq_alloc_queue(handle))<0) {
fprintf(stderr, "Cannot allocate queue: %s\n", snd_strerror(queue));
return;
}
printf("Queue ID = %i\n", queue);
event_sender_filter(handle);
if ((err = snd_seq_nonblock(handle, 1))<0)
fprintf(stderr, "Cannot set nonblock mode: %s\n", snd_strerror(err));
snd_seq_port_info_alloca(&pinfo);
snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_READ);
snd_seq_port_info_set_name(pinfo, "Output");
if ((err = snd_seq_create_port(handle, pinfo)) < 0) {
fprintf(stderr, "Cannot create output port: %s\n", snd_strerror(err));
return;
}
port = snd_seq_port_info_get_port(pinfo);
snd_seq_port_subscribe_alloca(&sub);
addr.client = client;
addr.port = port;
snd_seq_port_subscribe_set_sender(sub, &addr);
for (max = 0; max < argc; max++) {
ptr = argv[max];
if (!ptr)
continue;
if (!strcmp(ptr, "pcm")) {
pcm_flag = 1;
continue;
}
if (sscanf(ptr, "%i.%i", &v1, &v2) != 2) {
fprintf(stderr, "Wrong argument '%s'...\n", argv[max]);
return;
}
addr.client = v1;
addr.port = v2;
snd_seq_port_subscribe_set_dest(sub, &addr);
if ((err = snd_seq_subscribe_port(handle, sub))<0) {
fprintf(stderr, "Cannot subscribe port %i from client %i: %s\n", v2, v1, snd_strerror(err));
return;
}
}
printf("Destination client = %i, port = %i\n", addr.client, addr.port);
#ifdef USE_PCM
if (pcm_flag) {
if ((err = snd_pcm_open(&phandle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
fprintf(stderr, "Playback open error: %s\n", snd_strerror(err));
exit(0);
}
set_hwparams(phandle);
pbuf = calloc(1, period_size * 4);
if (pbuf == NULL) {
fprintf(stderr, "No enough memory...\n");
exit(0);
}
}
#endif
event_sender_start_timer(handle, client, queue, phandle);
/* send the first event */
send_event(handle, queue, client, port, &addr, &time);
#ifdef USE_PCM
if (phandle)
max += snd_pcm_poll_descriptors_count(phandle);
#endif
pfds = alloca(sizeof(*pfds) * max);
while (1) {
int nseqs = snd_seq_poll_descriptors_count(handle, POLLOUT|POLLIN);
if (snd_seq_event_output_pending(handle))
snd_seq_poll_descriptors(handle, pfds, nseqs, POLLOUT|POLLIN);
else
snd_seq_poll_descriptors(handle, pfds, nseqs, POLLIN);
max = nseqs;
#ifdef USE_PCM
if (phandle) {
int pmax = snd_pcm_poll_descriptors_count(phandle);
snd_seq_poll_descriptors(phandle, pfds + max, pmax);
max += pmax;
}
#endif
if (poll(pfds, max, -1) < 0)
break;
#ifdef USE_PCM
if (phandle && (pfds[nseqs].revents & POLLOUT)) {
if (snd_pcm_writei(phandle, pbuf, period_size) != period_size) {
fprintf(stderr, "Playback write error!!\n");
exit(0);
}
}
#endif
if (pfds[0].revents & POLLOUT)
snd_seq_drain_output(handle);
if (pfds[0].revents & POLLIN) {
do {
if ((err = snd_seq_event_input(handle, &ev))<0)
break;
if (!ev)
continue;
if (ev->type == SND_SEQ_EVENT_ECHO)
send_event(handle, queue, client, port, &addr, &time);
decode_event(ev);
snd_seq_free_event(ev);
} while (err > 0);
}
}
}