mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-12-16 08:56:42 -05:00
Sequencer changes (pool per client) by Takashi Iwai <iwai@ww.uni-erlangen.de>
This commit is contained in:
parent
dc126564c7
commit
d00535cc1b
3 changed files with 439 additions and 576 deletions
|
|
@ -44,6 +44,8 @@ int snd_seq_get_queue_client(snd_seq_t *handle, int q, snd_seq_queue_client_t *q
|
||||||
int snd_seq_set_queue_client(snd_seq_t *handle, int q, snd_seq_queue_client_t *queue);
|
int snd_seq_set_queue_client(snd_seq_t *handle, int q, snd_seq_queue_client_t *queue);
|
||||||
int snd_seq_alloc_queue(snd_seq_t *handle);
|
int snd_seq_alloc_queue(snd_seq_t *handle);
|
||||||
int snd_seq_free_queue(snd_seq_t *handle, int q);
|
int snd_seq_free_queue(snd_seq_t *handle, int q);
|
||||||
|
int snd_seq_get_client_pool(snd_seq_t *handle, snd_seq_client_pool_t * info);
|
||||||
|
int snd_seq_set_client_pool(snd_seq_t *handle, snd_seq_client_pool_t * info);
|
||||||
/* event routines */
|
/* event routines */
|
||||||
snd_seq_event_t *snd_seq_create_event(void);
|
snd_seq_event_t *snd_seq_create_event(void);
|
||||||
int snd_seq_free_event(snd_seq_event_t *ev);
|
int snd_seq_free_event(snd_seq_event_t *ev);
|
||||||
|
|
|
||||||
196
src/seq/seq.c
196
src/seq/seq.c
|
|
@ -108,12 +108,10 @@ int snd_seq_open(snd_seq_t **handle, int mode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_close(snd_seq_t *handle)
|
int snd_seq_close(snd_seq_t *seq)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq)
|
if (!seq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
res = close(seq->fd) < 0 ? -errno : 0;
|
res = close(seq->fd) < 0 ? -errno : 0;
|
||||||
|
|
@ -121,22 +119,17 @@ int snd_seq_close(snd_seq_t *handle)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_file_descriptor(snd_seq_t *handle)
|
int snd_seq_file_descriptor(snd_seq_t *seq)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq)
|
if (!seq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return seq->fd;
|
return seq->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_block_mode(snd_seq_t *handle, int enable)
|
int snd_seq_block_mode(snd_seq_t *seq, int enable)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
long flags;
|
long flags;
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq)
|
if (!seq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if ((flags = fcntl(seq->fd, F_GETFL)) < 0)
|
if ((flags = fcntl(seq->fd, F_GETFL)) < 0)
|
||||||
|
|
@ -150,21 +143,15 @@ int snd_seq_block_mode(snd_seq_t *handle, int enable)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_client_id(snd_seq_t *handle)
|
int snd_seq_client_id(snd_seq_t *seq)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq)
|
if (!seq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return seq->client;
|
return seq->client;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_system_info(snd_seq_t *handle, snd_seq_system_info_t * info)
|
int snd_seq_system_info(snd_seq_t *seq, snd_seq_system_info_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !info)
|
if (!seq || !info)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (ioctl(seq->fd, SND_SEQ_IOCTL_SYSTEM_INFO, info) < 0)
|
if (ioctl(seq->fd, SND_SEQ_IOCTL_SYSTEM_INFO, info) < 0)
|
||||||
|
|
@ -172,21 +159,15 @@ int snd_seq_system_info(snd_seq_t *handle, snd_seq_system_info_t * info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_get_client_info(snd_seq_t *handle, snd_seq_client_info_t * info)
|
int snd_seq_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !info)
|
if (!seq || !info)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return snd_seq_get_any_client_info(handle, seq->client, info);
|
return snd_seq_get_any_client_info(seq, seq->client, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_get_any_client_info(snd_seq_t *handle, int client, snd_seq_client_info_t * info)
|
int snd_seq_get_any_client_info(snd_seq_t *seq, int client, snd_seq_client_info_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !info || client < 0)
|
if (!seq || !info || client < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
bzero(info, sizeof(snd_seq_client_info_t));
|
bzero(info, sizeof(snd_seq_client_info_t));
|
||||||
|
|
@ -196,11 +177,8 @@ int snd_seq_get_any_client_info(snd_seq_t *handle, int client, snd_seq_client_in
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_set_client_info(snd_seq_t *handle, snd_seq_client_info_t * info)
|
int snd_seq_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !info)
|
if (!seq || !info)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
info->client = seq->client;
|
info->client = seq->client;
|
||||||
|
|
@ -210,11 +188,8 @@ int snd_seq_set_client_info(snd_seq_t *handle, snd_seq_client_info_t * info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_create_port(snd_seq_t *handle, snd_seq_port_info_t * port)
|
int snd_seq_create_port(snd_seq_t *seq, snd_seq_port_info_t * port)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !port)
|
if (!seq || !port)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
port->client = seq->client;
|
port->client = seq->client;
|
||||||
|
|
@ -223,11 +198,8 @@ int snd_seq_create_port(snd_seq_t *handle, snd_seq_port_info_t * port)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_delete_port(snd_seq_t *handle, snd_seq_port_info_t * port)
|
int snd_seq_delete_port(snd_seq_t *seq, snd_seq_port_info_t * port)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !port)
|
if (!seq || !port)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
port->client = seq->client;
|
port->client = seq->client;
|
||||||
|
|
@ -236,21 +208,15 @@ int snd_seq_delete_port(snd_seq_t *handle, snd_seq_port_info_t * port)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_get_port_info(snd_seq_t *handle, int port, snd_seq_port_info_t * info)
|
int snd_seq_get_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !info || port < 0)
|
if (!seq || !info || port < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return snd_seq_get_any_port_info(handle, seq->client, port, info);
|
return snd_seq_get_any_port_info(seq, seq->client, port, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_get_any_port_info(snd_seq_t *handle, int client, int port, snd_seq_port_info_t * info)
|
int snd_seq_get_any_port_info(snd_seq_t *seq, int client, int port, snd_seq_port_info_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !info || client < 0 || port < 0)
|
if (!seq || !info || client < 0 || port < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
bzero(info, sizeof(snd_seq_port_info_t));
|
bzero(info, sizeof(snd_seq_port_info_t));
|
||||||
|
|
@ -261,11 +227,8 @@ int snd_seq_get_any_port_info(snd_seq_t *handle, int client, int port, snd_seq_p
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_set_port_info(snd_seq_t *handle, int port, snd_seq_port_info_t * info)
|
int snd_seq_set_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !info || port < 0)
|
if (!seq || !info || port < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
info->port = port;
|
info->port = port;
|
||||||
|
|
@ -274,11 +237,8 @@ int snd_seq_set_port_info(snd_seq_t *handle, int port, snd_seq_port_info_t * inf
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_subscribe_port(snd_seq_t *handle, snd_seq_port_subscribe_t * sub)
|
int snd_seq_subscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !sub)
|
if (!seq || !sub)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (ioctl(seq->fd, SND_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0)
|
if (ioctl(seq->fd, SND_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0)
|
||||||
|
|
@ -286,11 +246,8 @@ int snd_seq_subscribe_port(snd_seq_t *handle, snd_seq_port_subscribe_t * sub)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_unsubscribe_port(snd_seq_t *handle, snd_seq_port_subscribe_t * sub)
|
int snd_seq_unsubscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !sub)
|
if (!seq || !sub)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (ioctl(seq->fd, SND_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0)
|
if (ioctl(seq->fd, SND_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0)
|
||||||
|
|
@ -298,11 +255,8 @@ int snd_seq_unsubscribe_port(snd_seq_t *handle, snd_seq_port_subscribe_t * sub)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_get_queue_status(snd_seq_t *handle, int q, snd_seq_queue_status_t * status)
|
int snd_seq_get_queue_status(snd_seq_t *seq, int q, snd_seq_queue_status_t * status)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !status)
|
if (!seq || !status)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
bzero(status, sizeof(snd_seq_queue_status_t));
|
bzero(status, sizeof(snd_seq_queue_status_t));
|
||||||
|
|
@ -312,11 +266,8 @@ int snd_seq_get_queue_status(snd_seq_t *handle, int q, snd_seq_queue_status_t *
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_get_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t * tempo)
|
int snd_seq_get_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !tempo)
|
if (!seq || !tempo)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
bzero(tempo, sizeof(snd_seq_queue_tempo_t));
|
bzero(tempo, sizeof(snd_seq_queue_tempo_t));
|
||||||
|
|
@ -326,11 +277,8 @@ int snd_seq_get_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t * te
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_set_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t * tempo)
|
int snd_seq_set_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !tempo)
|
if (!seq || !tempo)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
tempo->queue = q;
|
tempo->queue = q;
|
||||||
|
|
@ -339,11 +287,8 @@ int snd_seq_set_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t * te
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_get_queue_owner(snd_seq_t *handle, int q, snd_seq_queue_owner_t * owner)
|
int snd_seq_get_queue_owner(snd_seq_t *seq, int q, snd_seq_queue_owner_t * owner)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !owner)
|
if (!seq || !owner)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
bzero(owner, sizeof(snd_seq_queue_owner_t));
|
bzero(owner, sizeof(snd_seq_queue_owner_t));
|
||||||
|
|
@ -353,11 +298,8 @@ int snd_seq_get_queue_owner(snd_seq_t *handle, int q, snd_seq_queue_owner_t * ow
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_set_queue_owner(snd_seq_t *handle, int q, snd_seq_queue_owner_t * owner)
|
int snd_seq_set_queue_owner(snd_seq_t *seq, int q, snd_seq_queue_owner_t * owner)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !owner)
|
if (!seq || !owner)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
owner->queue = q;
|
owner->queue = q;
|
||||||
|
|
@ -366,11 +308,8 @@ int snd_seq_set_queue_owner(snd_seq_t *handle, int q, snd_seq_queue_owner_t * ow
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_get_queue_timer(snd_seq_t *handle, int q, snd_seq_queue_timer_t * timer)
|
int snd_seq_get_queue_timer(snd_seq_t *seq, int q, snd_seq_queue_timer_t * timer)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !timer)
|
if (!seq || !timer)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
bzero(timer, sizeof(snd_seq_queue_timer_t));
|
bzero(timer, sizeof(snd_seq_queue_timer_t));
|
||||||
|
|
@ -380,11 +319,8 @@ int snd_seq_get_queue_timer(snd_seq_t *handle, int q, snd_seq_queue_timer_t * ti
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_set_queue_timer(snd_seq_t *handle, int q, snd_seq_queue_timer_t * timer)
|
int snd_seq_set_queue_timer(snd_seq_t *seq, int q, snd_seq_queue_timer_t * timer)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !timer)
|
if (!seq || !timer)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
timer->queue = q;
|
timer->queue = q;
|
||||||
|
|
@ -393,11 +329,8 @@ int snd_seq_set_queue_timer(snd_seq_t *handle, int q, snd_seq_queue_timer_t * ti
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_get_queue_sync(snd_seq_t *handle, int q, snd_seq_queue_sync_t * sync)
|
int snd_seq_get_queue_sync(snd_seq_t *seq, int q, snd_seq_queue_sync_t * sync)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !sync)
|
if (!seq || !sync)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
bzero(sync, sizeof(snd_seq_queue_sync_t));
|
bzero(sync, sizeof(snd_seq_queue_sync_t));
|
||||||
|
|
@ -407,11 +340,8 @@ int snd_seq_get_queue_sync(snd_seq_t *handle, int q, snd_seq_queue_sync_t * sync
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_set_queue_sync(snd_seq_t *handle, int q, snd_seq_queue_sync_t * sync)
|
int snd_seq_set_queue_sync(snd_seq_t *seq, int q, snd_seq_queue_sync_t * sync)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !sync)
|
if (!seq || !sync)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
sync->queue = q;
|
sync->queue = q;
|
||||||
|
|
@ -420,11 +350,8 @@ int snd_seq_set_queue_sync(snd_seq_t *handle, int q, snd_seq_queue_sync_t * sync
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_get_queue_client(snd_seq_t *handle, int q, snd_seq_queue_client_t * info)
|
int snd_seq_get_queue_client(snd_seq_t *seq, int q, snd_seq_queue_client_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !info)
|
if (!seq || !info)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
bzero(info, sizeof(snd_seq_queue_client_t));
|
bzero(info, sizeof(snd_seq_queue_client_t));
|
||||||
|
|
@ -435,11 +362,8 @@ int snd_seq_get_queue_client(snd_seq_t *handle, int q, snd_seq_queue_client_t *
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_set_queue_client(snd_seq_t *handle, int q, snd_seq_queue_client_t * info)
|
int snd_seq_set_queue_client(snd_seq_t *seq, int q, snd_seq_queue_client_t * info)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !info)
|
if (!seq || !info)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
info->queue = q;
|
info->queue = q;
|
||||||
|
|
@ -449,47 +373,43 @@ int snd_seq_set_queue_client(snd_seq_t *handle, int q, snd_seq_queue_client_t *
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_alloc_queue(snd_seq_t *handle)
|
int snd_seq_alloc_queue(snd_seq_t *seq)
|
||||||
{
|
{
|
||||||
int i, err;
|
int i, err;
|
||||||
snd_seq_system_info_t sysinfo;
|
snd_seq_system_info_t sysinfo;
|
||||||
snd_seq_queue_owner_t owner;
|
snd_seq_queue_owner_t owner;
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq)
|
if (!seq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if ((err = snd_seq_system_info(handle, &sysinfo))<0)
|
if ((err = snd_seq_system_info(seq, &sysinfo))<0)
|
||||||
return err;
|
return err;
|
||||||
for (i = 0; i < sysinfo.queues; i++) {
|
for (i = 0; i < sysinfo.queues; i++) {
|
||||||
if ((err = snd_seq_get_queue_owner(handle, i, &owner))<0)
|
if ((err = snd_seq_get_queue_owner(seq, i, &owner))<0)
|
||||||
continue;
|
continue;
|
||||||
if (owner.locked)
|
if (owner.locked)
|
||||||
continue;
|
continue;
|
||||||
owner.locked = 1;
|
owner.locked = 1;
|
||||||
owner.owner = seq->client;
|
owner.owner = seq->client;
|
||||||
if ((err = snd_seq_set_queue_owner(handle, i, &owner))<0)
|
if ((err = snd_seq_set_queue_owner(seq, i, &owner))<0)
|
||||||
continue;
|
continue;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_free_queue(snd_seq_t *handle, int q)
|
int snd_seq_free_queue(snd_seq_t *seq, int q)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
snd_seq_t *seq;
|
|
||||||
snd_seq_queue_owner_t owner;
|
snd_seq_queue_owner_t owner;
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq)
|
if (!seq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if ((err = snd_seq_get_queue_owner(handle, q, &owner))<0)
|
if ((err = snd_seq_get_queue_owner(seq, q, &owner))<0)
|
||||||
return err;
|
return err;
|
||||||
if (owner.locked && owner.owner == seq->client) {
|
if (owner.locked && owner.owner == seq->client) {
|
||||||
owner.locked = 0;
|
owner.locked = 0;
|
||||||
owner.owner = -1;
|
owner.owner = -1;
|
||||||
if ((err = snd_seq_set_queue_owner(handle, q, &owner))<0)
|
if ((err = snd_seq_set_queue_owner(seq, q, &owner))<0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -537,17 +457,15 @@ int snd_seq_event_length(snd_seq_event_t *ev)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_event_output(snd_seq_t *handle, snd_seq_event_t *ev)
|
int snd_seq_event_output(snd_seq_t *seq, snd_seq_event_t *ev)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq || !ev)
|
if (!seq || !ev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
len = snd_seq_event_length(ev);
|
len = snd_seq_event_length(ev);
|
||||||
if ((seq->obufsize - seq->obufused) < len) {
|
if ((seq->obufsize - seq->obufused) < len) {
|
||||||
snd_seq_flush_output(handle);
|
snd_seq_flush_output(seq);
|
||||||
if ((seq->obufsize - seq->obufused) < len)
|
if ((seq->obufsize - seq->obufused) < len)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
@ -659,15 +577,13 @@ static int snd_seq_decode_event(char **buf, int *len, snd_seq_event_t *ev)
|
||||||
* Current implementation uses FIFO cache.
|
* Current implementation uses FIFO cache.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int snd_seq_event_input(snd_seq_t *handle, snd_seq_event_t **ev)
|
int snd_seq_event_input(snd_seq_t *seq, snd_seq_event_t **ev)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
snd_seq_cell_t *cell;
|
snd_seq_cell_t *cell;
|
||||||
char *buf;
|
char *buf;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
*ev = NULL;
|
*ev = NULL;
|
||||||
seq = handle;
|
|
||||||
if (!seq)
|
if (!seq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (snd_seq_input_cell_available(seq)) {
|
if (snd_seq_input_cell_available(seq)) {
|
||||||
|
|
@ -705,19 +621,17 @@ int snd_seq_event_input(snd_seq_t *handle, snd_seq_event_t **ev)
|
||||||
return seq->cells;
|
return seq->cells;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_flush_output(snd_seq_t *handle)
|
int snd_seq_flush_output(snd_seq_t *seq)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq)
|
if (!seq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (seq->obufused <= 0)
|
if (seq->obufused <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
result = write(seq->fd, seq->obuf, seq->obufused);
|
result = write(seq->fd, seq->obuf, seq->obufused);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
snd_seq_drain_output(handle);
|
snd_seq_drain_output(seq);
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
if (result < seq->obufused)
|
if (result < seq->obufused)
|
||||||
|
|
@ -726,22 +640,16 @@ int snd_seq_flush_output(snd_seq_t *handle)
|
||||||
return seq->obufused;
|
return seq->obufused;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_drain_output(snd_seq_t *handle)
|
int snd_seq_drain_output(snd_seq_t *seq)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq)
|
if (!seq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
seq->obufused = 0;
|
seq->obufused = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snd_seq_drain_input(snd_seq_t *handle)
|
int snd_seq_drain_input(snd_seq_t *seq)
|
||||||
{
|
{
|
||||||
snd_seq_t *seq;
|
|
||||||
|
|
||||||
seq = handle;
|
|
||||||
if (!seq)
|
if (!seq)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
while (snd_seq_input_cell_available(seq))
|
while (snd_seq_input_cell_available(seq))
|
||||||
|
|
@ -749,6 +657,26 @@ int snd_seq_drain_input(snd_seq_t *handle)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int snd_seq_get_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
|
||||||
|
{
|
||||||
|
if (!seq || !info)
|
||||||
|
return -EINVAL;
|
||||||
|
info->client = seq->client;
|
||||||
|
if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_CLIENT_POOL, info) < 0)
|
||||||
|
return -errno;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int snd_seq_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
|
||||||
|
{
|
||||||
|
if (!seq || !info)
|
||||||
|
return -EINVAL;
|
||||||
|
info->client = seq->client;
|
||||||
|
if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_CLIENT_POOL, info) < 0)
|
||||||
|
return -errno;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void snd_seq_set_bit(int nr, void *array)
|
void snd_seq_set_bit(int nr, void *array)
|
||||||
{
|
{
|
||||||
((unsigned int *)array)[nr >> 5] |= 1UL << (nr & 31);
|
((unsigned int *)array)[nr >> 5] |= 1UL << (nr & 31);
|
||||||
|
|
|
||||||
661
test/playmidi1.c
661
test/playmidi1.c
|
|
@ -7,6 +7,11 @@
|
||||||
* Modified so that this uses alsa-lib
|
* Modified so that this uses alsa-lib
|
||||||
* 1999 Jan. by Isaku Yamahata <yamahata@kusm.kyoto-u.ac.jp>
|
* 1999 Jan. by Isaku Yamahata <yamahata@kusm.kyoto-u.ac.jp>
|
||||||
*
|
*
|
||||||
|
* 19990604 Takashi Iwai <iwai@ww.uni-erlangen.de>
|
||||||
|
* - use blocking mode
|
||||||
|
* - fix tempo event bug
|
||||||
|
* - add command line options
|
||||||
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
|
@ -23,19 +28,13 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* define this if you want to send real-time time stamps instead of midi ticks to the ALSA sequencer */
|
|
||||||
/*#define USE_REALTIME */
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sched.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "midifile.h" /* SMF library header */
|
#include "midifile.h" /* SMF library header */
|
||||||
|
|
@ -43,24 +42,29 @@
|
||||||
|
|
||||||
#include "../include/asoundlib.h"
|
#include "../include/asoundlib.h"
|
||||||
|
|
||||||
//#define DEST_QUEUE_NUMBER 0
|
/* define this if you want to send real-time time stamps instead of midi ticks to the ALSA sequencer */
|
||||||
|
/* #define USE_REALTIME */
|
||||||
|
|
||||||
|
/* define this if you want to control event buffering by blocking mode */
|
||||||
|
#define USE_BLOCKING_MODE
|
||||||
|
|
||||||
|
/* default destination queue, client and port numbers */
|
||||||
#define DEST_QUEUE_NUMBER 7
|
#define DEST_QUEUE_NUMBER 7
|
||||||
//#define DEST_CLIENT_NUMBER 64
|
#define DEST_CLIENT_NUMBER 65
|
||||||
#define DEST_CLIENT_NUMBER 72
|
|
||||||
//#define DEST_CLIENT_NUMBER 128
|
|
||||||
//#define DEST_CLIENT_NUMBER 255
|
|
||||||
//#define DEST_CLIENT_NUMBER SND_SEQ_ADDRESS_BROADCAST
|
|
||||||
#define DEST_PORT_NUMBER 0
|
#define DEST_PORT_NUMBER 0
|
||||||
|
|
||||||
//#define USE_REALTIME
|
/* event pool size */
|
||||||
|
#define WRITE_POOL_SIZE 200
|
||||||
|
#define WRITE_POOL_SPACE 10
|
||||||
|
#define READ_POOL_SIZE 10 /* we need read pool only for echoing */
|
||||||
|
|
||||||
FILE *F;
|
static FILE *F;
|
||||||
snd_seq_t *seq_handle = NULL;
|
static snd_seq_t *seq_handle = NULL;
|
||||||
int ppq = 96;
|
static int ppq = 96;
|
||||||
|
|
||||||
double local_secs = 0;
|
static double local_secs = 0;
|
||||||
int local_ticks = 0;
|
static int local_ticks = 0;
|
||||||
int local_tempo = 500000;
|
static int local_tempo = 500000;
|
||||||
|
|
||||||
static int dest_queue = DEST_QUEUE_NUMBER;
|
static int dest_queue = DEST_QUEUE_NUMBER;
|
||||||
static int dest_client = DEST_CLIENT_NUMBER;
|
static int dest_client = DEST_CLIENT_NUMBER;
|
||||||
|
|
@ -68,129 +72,114 @@ static int dest_port = DEST_PORT_NUMBER;
|
||||||
static int source_channel = 0;
|
static int source_channel = 0;
|
||||||
static int source_port = 0;
|
static int source_port = 0;
|
||||||
|
|
||||||
|
static int verbose = 0;
|
||||||
|
|
||||||
extern void alsa_start_timer(void);
|
#define VERB_INFO 1
|
||||||
extern void alsa_stop_timer(void);
|
#define VERB_MUCH 2
|
||||||
|
#define VERB_EVENT 3
|
||||||
|
|
||||||
|
static void alsa_start_timer(void);
|
||||||
|
static void alsa_stop_timer(void);
|
||||||
|
|
||||||
|
|
||||||
static inline double tick2time_dbl(int tick)
|
static inline double tick2time_dbl(int tick)
|
||||||
{
|
{
|
||||||
return local_secs + ((double) (tick - local_ticks) * (double) local_tempo * 1.0E-9 / (double) ppq);
|
return local_secs + ((double) (tick - local_ticks) * (double) local_tempo * 1.0E-6 / (double) ppq);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
#ifdef USE_REALTIME
|
||||||
static void tick2time(snd_seq_real_time_t * tm, int tick)
|
static void tick2time(snd_seq_real_time_t * tm, int tick)
|
||||||
{
|
{
|
||||||
double secs = tick2time_dbl(tick);
|
double secs = tick2time_dbl(tick);
|
||||||
|
|
||||||
//double secs = ((double) tick * (double) local_tempo * 1.0E-6 / (double) ppq);
|
|
||||||
|
|
||||||
tm->tv_sec = secs;
|
tm->tv_sec = secs;
|
||||||
tm->tv_nsec = (secs - tm->tv_sec) * 1.0E9;
|
tm->tv_nsec = (secs - tm->tv_sec) * 1.0E9;
|
||||||
|
|
||||||
//printf("secs = %lf = %d.%09d\n", secs, tm->tv_sec, tm->tv_nsec);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* sleep until sequencer has reached specified timestamp, to guard that we play too much events ahead */
|
|
||||||
void sleep_seq(int tick)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
snd_seq_queue_info_t queue_info;
|
|
||||||
const int COUNT_MAX = 500;
|
|
||||||
const int COUNT_MIN = 50;
|
|
||||||
static int count = 0;
|
|
||||||
count++;
|
|
||||||
if (count >= COUNT_MAX)
|
|
||||||
{
|
|
||||||
while (snd_seq_flush_output(seq_handle) > COUNT_MIN)
|
|
||||||
sched_yield ();
|
|
||||||
count = 0;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
|
#ifdef USE_BLOCKING_MODE
|
||||||
/* write event to ALSA sequencer */
|
/* write event - using blocking mode */
|
||||||
void write_ev_im(snd_seq_event_t * ev)
|
static void write_ev_im(snd_seq_event_t *ev)
|
||||||
{
|
{
|
||||||
int written;
|
int written;
|
||||||
|
|
||||||
ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK;
|
|
||||||
ev->flags |= SND_SEQ_EVENT_LENGTH_FIXED;
|
|
||||||
|
|
||||||
|
|
||||||
written = -ENOMEM;
|
|
||||||
while (written<0) {
|
|
||||||
written = snd_seq_event_output(seq_handle, ev);
|
written = snd_seq_event_output(seq_handle, ev);
|
||||||
if (written < 0) {
|
if (written < 0) {
|
||||||
//printf("written = %i (%s)\n", written, snd_strerror(written));
|
printf("written = %i (%s)\n", written, snd_strerror(written));
|
||||||
sleep(1);
|
exit(1);
|
||||||
//sched_yield ();
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* write event - using select syscall */
|
||||||
|
static void write_ev_im(snd_seq_event_t *ev)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
while ((rc = snd_seq_event_output(seq_handle, ev)) < 0) {
|
||||||
|
int seqfd;
|
||||||
|
fd_set fds;
|
||||||
|
seqfd = snd_seq_file_descriptor(seq_handle);
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(seqfd, &fds);
|
||||||
|
if ((rc = select(seqfd + 1, NULL, &fds, NULL, NULL)) < 0) {
|
||||||
|
printf("select error = %i (%s)\n", rc, snd_strerror(rc));
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* write event to ALSA sequencer */
|
/* write event to ALSA sequencer */
|
||||||
void write_ev(snd_seq_event_t * ev)
|
static void write_ev(snd_seq_event_t * ev)
|
||||||
{
|
{
|
||||||
sleep_seq(ev->time.tick-ppq);
|
ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK;
|
||||||
|
ev->flags |= SND_SEQ_EVENT_LENGTH_FIXED;
|
||||||
write_ev_im(ev);
|
write_ev_im(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write variable length event to ALSA sequencer */
|
/* write variable length event to ALSA sequencer */
|
||||||
void write_ev_var(snd_seq_event_t * ev, int len, void *ptr)
|
static void write_ev_var(snd_seq_event_t * ev, int len, void *ptr)
|
||||||
{
|
{
|
||||||
int written;
|
|
||||||
|
|
||||||
sleep_seq(ev->time.tick+ppq);
|
|
||||||
|
|
||||||
ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK;
|
ev->flags &= ~SND_SEQ_EVENT_LENGTH_MASK;
|
||||||
ev->flags |= SND_SEQ_EVENT_LENGTH_VARIABLE;
|
ev->flags |= SND_SEQ_EVENT_LENGTH_VARIABLE;
|
||||||
ev->data.ext.len = len;
|
ev->data.ext.len = len;
|
||||||
ev->data.ext.ptr = ptr;
|
ev->data.ext.ptr = ptr;
|
||||||
|
write_ev_im(ev);
|
||||||
written = -ENOMEM;
|
|
||||||
while (written<0) {
|
|
||||||
written = snd_seq_event_output (seq_handle, ev);
|
|
||||||
if (written<0) {
|
|
||||||
//printf("written = %i (%s)\n", written, snd_strerror(written));
|
|
||||||
sleep(1);
|
|
||||||
//sched_yield ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read byte */
|
||||||
int mygetc(void)
|
static int mygetc(void)
|
||||||
{
|
{
|
||||||
return (getc(F));
|
return getc(F);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mytext(int type, int leng, char *msg)
|
/* print out text */
|
||||||
|
static void mytext(int type, int leng, char *msg)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
char *ep = msg + leng;
|
char *ep = msg + leng;
|
||||||
|
|
||||||
|
if (verbose >= VERB_INFO) {
|
||||||
for (p = msg; p < ep; p++)
|
for (p = msg; p < ep; p++)
|
||||||
putchar(isprint(*p) ? *p : '?');
|
putchar(isprint(*p) ? *p : '?');
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void do_header(int format, int ntracks, int division)
|
static void do_header(int format, int ntracks, int division)
|
||||||
{
|
{
|
||||||
|
snd_seq_queue_tempo_t tempo;
|
||||||
|
|
||||||
|
if (verbose >= VERB_INFO)
|
||||||
printf("smf format %d, %d tracks, %d ppq\n", format, ntracks, division);
|
printf("smf format %d, %d tracks, %d ppq\n", format, ntracks, division);
|
||||||
ppq = division;
|
ppq = division;
|
||||||
|
|
||||||
if ((format != 0) || (ntracks != 1)) {
|
if (format != 0 || ntracks != 1) {
|
||||||
printf("This player does not support merging of tracks.\n");
|
printf("This player does not support merging of tracks.\n");
|
||||||
alsa_stop_timer();
|
alsa_stop_timer();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* set ppq */
|
/* set ppq */
|
||||||
{
|
/* ppq must be set before starting timer */
|
||||||
snd_seq_queue_tempo_t tempo;
|
|
||||||
if (snd_seq_get_queue_tempo(seq_handle, dest_queue, &tempo) < 0) {
|
if (snd_seq_get_queue_tempo(seq_handle, dest_queue, &tempo) < 0) {
|
||||||
perror("get_queue_tempo");
|
perror("get_queue_tempo");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
@ -201,105 +190,113 @@ void do_header(int format, int ntracks, int division)
|
||||||
perror("set_queue_tempo");
|
perror("set_queue_tempo");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
if (verbose >= VERB_INFO)
|
||||||
printf("ALSA Timer updated, PPQ = %d\n", tempo.ppq);
|
printf("ALSA Timer updated, PPQ = %d\n", tempo.ppq);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* start playing... */
|
/* start playing... */
|
||||||
alsa_start_timer();
|
alsa_start_timer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_tempo(int us)
|
/* fill normal event header */
|
||||||
|
static void set_event_header(snd_seq_event_t *ev, int type, int chan)
|
||||||
|
{
|
||||||
|
ev->source.port = source_port;
|
||||||
|
ev->source.channel = source_channel;
|
||||||
|
|
||||||
|
ev->dest.queue = dest_queue;
|
||||||
|
ev->dest.client = dest_client;
|
||||||
|
ev->dest.port = dest_port;
|
||||||
|
ev->dest.channel = chan;
|
||||||
|
|
||||||
|
#ifdef USE_REALTIME
|
||||||
|
ev->flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
||||||
|
tick2time(&ev->time.real, Mf_currtime);
|
||||||
|
#else
|
||||||
|
ev->flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
||||||
|
ev->time.tick = Mf_currtime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ev->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill timer event header */
|
||||||
|
static void set_timer_event_header(snd_seq_event_t *ev, int type)
|
||||||
|
{
|
||||||
|
ev->source.port = source_port;
|
||||||
|
ev->source.channel = 0;
|
||||||
|
|
||||||
|
ev->dest.queue = dest_queue;
|
||||||
|
ev->dest.client = SND_SEQ_CLIENT_SYSTEM; /* system */
|
||||||
|
ev->dest.port = SND_SEQ_PORT_SYSTEM_TIMER; /* timer */
|
||||||
|
ev->dest.channel = 0; /* don't care */
|
||||||
|
|
||||||
|
#ifdef USE_REALTIME
|
||||||
|
ev->flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
||||||
|
tick2time(&ev->time.real, Mf_currtime);
|
||||||
|
#else
|
||||||
|
ev->flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
||||||
|
ev->time.tick = Mf_currtime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ev->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start timer */
|
||||||
|
static void alsa_start_timer(void)
|
||||||
{
|
{
|
||||||
double bpm;
|
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
bpm = 60.0E6 / (double) us;
|
set_timer_event_header(&ev, SND_SEQ_EVENT_START);
|
||||||
|
#ifdef USE_REALTIME
|
||||||
|
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL;
|
||||||
|
ev.time.real.tv_sec = 0;
|
||||||
|
ev.time.real.tv_nsec = 0;
|
||||||
|
#else
|
||||||
|
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_REL;
|
||||||
|
ev.time.tick = Mf_currtime;
|
||||||
|
#endif
|
||||||
|
|
||||||
printf("tempo = %d us/beat\n", us);
|
write_ev(&ev);
|
||||||
printf("tempo = %.2f bpm\n", bpm);
|
}
|
||||||
|
|
||||||
|
/* stop timer */
|
||||||
|
static void alsa_stop_timer(void)
|
||||||
|
{
|
||||||
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
|
set_timer_event_header(&ev, SND_SEQ_EVENT_STOP);
|
||||||
|
write_ev(&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* change tempo */
|
||||||
|
static void do_tempo(int us)
|
||||||
|
{
|
||||||
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
|
if (verbose >= VERB_MUCH) {
|
||||||
|
double bpm;
|
||||||
|
bpm = 60.0E6 / (double) us;
|
||||||
|
printf("Tempo %d us/beat, %.2f bpm\n", us, bpm);
|
||||||
|
}
|
||||||
|
|
||||||
/* store new tempo and timestamp of tempo change */
|
/* store new tempo and timestamp of tempo change */
|
||||||
local_secs = tick2time_dbl(Mf_currtime);
|
local_secs = tick2time_dbl(Mf_currtime);
|
||||||
local_ticks = Mf_currtime;
|
local_ticks = Mf_currtime;
|
||||||
local_tempo = us;
|
local_tempo = us;
|
||||||
|
|
||||||
|
set_timer_event_header(&ev, SND_SEQ_EVENT_TEMPO);
|
||||||
/* and send tempo change event to the sequencer.... */
|
|
||||||
ev.source.port = dest_port;
|
|
||||||
ev.source.channel = source_channel;
|
|
||||||
|
|
||||||
ev.dest.queue = dest_queue;
|
|
||||||
//ev.dest.client = dest_client; /* broadcast */
|
|
||||||
ev.dest.client = 255; /* broadcast */
|
|
||||||
ev.dest.port = 0;
|
|
||||||
ev.dest.channel = 0; /* don't care */
|
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
tick2time(&ev.time.real, Mf_currtime);
|
|
||||||
#else
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
ev.time.tick = Mf_currtime;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_TEMPO;
|
|
||||||
ev.data.control.value = us;
|
ev.data.control.value = us;
|
||||||
|
|
||||||
write_ev_im(&ev);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_noteon(int chan, int pitch, int vol)
|
|
||||||
{
|
|
||||||
snd_seq_event_t ev;
|
|
||||||
|
|
||||||
ev.source.port = dest_port;
|
|
||||||
ev.source.channel = source_channel;
|
|
||||||
|
|
||||||
ev.dest.queue = dest_queue;
|
|
||||||
ev.dest.client = dest_client;
|
|
||||||
ev.dest.port = dest_port;
|
|
||||||
ev.dest.channel = chan;
|
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
tick2time(&ev.time.real, Mf_currtime);
|
|
||||||
#else
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
ev.time.tick = Mf_currtime;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_NOTEON;
|
|
||||||
ev.data.note.note = pitch;
|
|
||||||
ev.data.note.velocity = vol;
|
|
||||||
|
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void do_noteon(int chan, int pitch, int vol)
|
||||||
void do_noteoff(int chan, int pitch, int vol)
|
|
||||||
{
|
{
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
ev.source.port = dest_port;
|
if (verbose >= VERB_EVENT)
|
||||||
ev.source.channel = source_channel;
|
printf("NoteOn (%d) %d %d\n", chan, pitch, vol);
|
||||||
|
set_event_header(&ev, SND_SEQ_EVENT_NOTEON, chan);
|
||||||
ev.dest.queue = dest_queue;
|
|
||||||
ev.dest.client = dest_client;
|
|
||||||
ev.dest.port = dest_port;
|
|
||||||
ev.dest.channel = chan;
|
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
tick2time(&ev.time.real, Mf_currtime);
|
|
||||||
#else
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
ev.time.tick = Mf_currtime;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_NOTEOFF;
|
|
||||||
ev.data.note.note = pitch;
|
ev.data.note.note = pitch;
|
||||||
ev.data.note.velocity = vol;
|
ev.data.note.velocity = vol;
|
||||||
|
|
||||||
|
|
@ -307,54 +304,40 @@ void do_noteoff(int chan, int pitch, int vol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void do_program(int chan, int program)
|
static void do_noteoff(int chan, int pitch, int vol)
|
||||||
{
|
{
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
ev.source.port = dest_port;
|
if (verbose >= VERB_EVENT)
|
||||||
ev.source.channel = source_channel;
|
printf("NoteOff (%d) %d %d\n", chan, pitch, vol);
|
||||||
|
set_event_header(&ev, SND_SEQ_EVENT_NOTEOFF, chan);
|
||||||
|
ev.data.note.note = pitch;
|
||||||
|
ev.data.note.velocity = vol;
|
||||||
|
|
||||||
ev.dest.queue = dest_queue;
|
write_ev(&ev);
|
||||||
ev.dest.client = dest_client;
|
}
|
||||||
ev.dest.port = dest_port;
|
|
||||||
ev.dest.channel = chan;
|
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
tick2time(&ev.time.real, Mf_currtime);
|
|
||||||
#else
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
ev.time.tick = Mf_currtime;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_PGMCHANGE;
|
static void do_program(int chan, int program)
|
||||||
|
{
|
||||||
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
|
if (verbose >= VERB_EVENT)
|
||||||
|
printf("Program (%d) %d\n", chan, program);
|
||||||
|
set_event_header(&ev, SND_SEQ_EVENT_PGMCHANGE, chan);
|
||||||
ev.data.control.value = program;
|
ev.data.control.value = program;
|
||||||
|
|
||||||
write_ev_im(&ev);
|
write_ev(&ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void do_parameter(int chan, int control, int value)
|
static void do_parameter(int chan, int control, int value)
|
||||||
{
|
{
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
ev.source.port = dest_port;
|
if (verbose >= VERB_EVENT)
|
||||||
ev.source.channel = source_channel;
|
printf("Control (%d) %d %d\n", chan, control, value);
|
||||||
|
set_event_header(&ev, SND_SEQ_EVENT_CONTROLLER, chan);
|
||||||
ev.dest.queue = dest_queue;
|
|
||||||
ev.dest.client = dest_client;
|
|
||||||
ev.dest.port = dest_port;
|
|
||||||
ev.dest.channel = chan;
|
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
tick2time(&ev.time.real, Mf_currtime);
|
|
||||||
#else
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
ev.time.tick = Mf_currtime;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_CONTROLLER;
|
|
||||||
ev.data.control.param = control;
|
ev.data.control.param = control;
|
||||||
ev.data.control.value = value;
|
ev.data.control.value = value;
|
||||||
|
|
||||||
|
|
@ -362,131 +345,75 @@ void do_parameter(int chan, int control, int value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void do_pitchbend(int chan, int lsb, int msb)
|
static void do_pitchbend(int chan, int lsb, int msb)
|
||||||
{ /* !@#$% lsb & msb are in wrong order in docs */
|
{ /* !@#$% lsb & msb are in wrong order in docs */
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
ev.source.port = dest_port;
|
if (verbose >= VERB_EVENT)
|
||||||
ev.source.channel = source_channel;
|
printf("Pitchbend (%d) %d %d\n", chan, lsb, msb);
|
||||||
|
set_event_header(&ev, SND_SEQ_EVENT_PITCHBEND, chan);
|
||||||
ev.dest.queue = dest_queue;
|
|
||||||
ev.dest.client = dest_client;
|
|
||||||
ev.dest.port = dest_port;
|
|
||||||
ev.dest.channel = chan;
|
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
tick2time(&ev.time.real, Mf_currtime);
|
|
||||||
#else
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
ev.time.tick = Mf_currtime;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_PITCHBEND;
|
|
||||||
ev.data.control.value = (lsb + (msb << 7)) - 8192;
|
ev.data.control.value = (lsb + (msb << 7)) - 8192;
|
||||||
|
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_pressure(int chan, int pitch, int pressure)
|
static void do_pressure(int chan, int pitch, int pressure)
|
||||||
{
|
{
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
ev.source.port = dest_port;
|
if (verbose >= VERB_EVENT)
|
||||||
ev.source.channel = source_channel;
|
printf("KeyPress (%d) %d %d\n", chan, pitch, pressure);
|
||||||
|
set_event_header(&ev, SND_SEQ_EVENT_KEYPRESS, chan);
|
||||||
ev.dest.queue = dest_queue;
|
|
||||||
ev.dest.client = dest_client;
|
|
||||||
ev.dest.port = dest_port;
|
|
||||||
ev.dest.channel = chan;
|
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
tick2time(&ev.time.real, Mf_currtime);
|
|
||||||
#else
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
ev.time.tick = Mf_currtime;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_KEYPRESS;
|
|
||||||
ev.data.control.param = pitch;
|
ev.data.control.param = pitch;
|
||||||
ev.data.control.value = pressure;
|
ev.data.control.value = pressure;
|
||||||
|
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_chanpressure(int chan, int pressure)
|
static void do_chanpressure(int chan, int pressure)
|
||||||
{
|
{
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
ev.source.port = dest_port;
|
if (verbose >= VERB_EVENT)
|
||||||
ev.source.channel = source_channel;
|
printf("ChanPress (%d) %d\n", chan, pressure);
|
||||||
|
set_event_header(&ev, SND_SEQ_EVENT_CHANPRESS, chan);
|
||||||
ev.dest.queue = dest_queue;
|
|
||||||
ev.dest.client = dest_client;
|
|
||||||
ev.dest.port = dest_port;
|
|
||||||
ev.dest.channel = chan;
|
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
tick2time(&ev.time.real, Mf_currtime);
|
|
||||||
#else
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
ev.time.tick = Mf_currtime;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_CHANPRESS;
|
|
||||||
ev.data.control.value = pressure;
|
ev.data.control.value = pressure;
|
||||||
|
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_sysex(int len, char *msg)
|
static void do_sysex(int len, char *msg)
|
||||||
{
|
{
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
#if 0
|
if (verbose >= VERB_MUCH) {
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
printf("Sysex, len=%d\n", len);
|
printf("Sysex, len=%d\n", len);
|
||||||
for (c = 0; c < len; c++) {
|
for (c = 0; c < len; c++) {
|
||||||
printf(" %3d : %02x\n", c, (unsigned char) msg[c]);
|
printf(" %02x", (unsigned char)msg[c]);
|
||||||
|
if (c % 16 == 15)
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
if (c % 16 != 15)
|
||||||
|
putchar('\n');
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
ev.source.port = dest_port;
|
|
||||||
ev.source.channel = source_channel;
|
|
||||||
|
|
||||||
ev.dest.queue = dest_queue;
|
|
||||||
ev.dest.client = dest_client;
|
|
||||||
ev.dest.port = dest_port;
|
|
||||||
ev.dest.channel = 0; /* don't care */
|
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
tick2time(&ev.time.real, Mf_currtime);
|
|
||||||
#else
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
ev.time.tick = Mf_currtime;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_SYSEX;
|
|
||||||
|
|
||||||
|
set_event_header(&ev, SND_SEQ_EVENT_SYSEX, 0);
|
||||||
write_ev_var(&ev, len, msg);
|
write_ev_var(&ev, len, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**/
|
/* synchronize to the end of event */
|
||||||
void alsa_sync ()
|
static void alsa_sync(void)
|
||||||
{
|
{
|
||||||
int left;
|
int left;
|
||||||
snd_seq_event_t* input_event;
|
snd_seq_event_t* input_event;
|
||||||
|
|
||||||
//send echo event to self client.
|
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
|
/* send echo event to self client. */
|
||||||
|
if (verbose >= VERB_MUCH)
|
||||||
printf("alsa_sync syncing... send ECHO(%d) event to myself. time=%f\n",
|
printf("alsa_sync syncing... send ECHO(%d) event to myself. time=%f\n",
|
||||||
SND_SEQ_EVENT_ECHO, (double) Mf_currtime+1);
|
SND_SEQ_EVENT_ECHO, (double) Mf_currtime+1);
|
||||||
ev.source.port = dest_port;
|
ev.source.port = source_port;
|
||||||
ev.source.channel = source_channel;
|
ev.source.channel = source_channel;
|
||||||
ev.dest.queue = dest_queue;
|
ev.dest.queue = dest_queue;
|
||||||
ev.dest.client = snd_seq_client_id(seq_handle);
|
ev.dest.client = snd_seq_client_id(seq_handle);
|
||||||
|
|
@ -501,84 +428,66 @@ void alsa_sync ()
|
||||||
ev.time.tick = Mf_currtime+1;
|
ev.time.tick = Mf_currtime+1;
|
||||||
#endif
|
#endif
|
||||||
ev.type = SND_SEQ_EVENT_ECHO;
|
ev.type = SND_SEQ_EVENT_ECHO;
|
||||||
write_ev_im (&ev);
|
write_ev(&ev);
|
||||||
|
|
||||||
//dump buffer
|
/* dump buffer */
|
||||||
left = snd_seq_flush_output(seq_handle);
|
left = snd_seq_flush_output(seq_handle);
|
||||||
while (left > 0)
|
|
||||||
{
|
|
||||||
sched_yield ();
|
|
||||||
left = snd_seq_flush_output (seq_handle);
|
|
||||||
if (left < 0)
|
|
||||||
{
|
|
||||||
printf ("alsa_sync error!:%s\n", snd_strerror (left));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//wait the echo event which I sent.
|
/* wait the echo event which I sent. */
|
||||||
|
#ifdef USE_BLOCKING_MODE
|
||||||
|
/* read event - blocked until any event is read */
|
||||||
left = snd_seq_event_input(seq_handle, &input_event);
|
left = snd_seq_event_input(seq_handle, &input_event);
|
||||||
if (left < 0)
|
#else
|
||||||
{
|
/* read event - using select syscall */
|
||||||
|
while ((left = snd_seq_event_input(seq_handle, &input_event)) >= 0 &&
|
||||||
|
input_event == NULL) {
|
||||||
|
int seqfd;
|
||||||
|
fd_set fds;
|
||||||
|
seqfd = snd_seq_file_descriptor(seq_handle);
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(seqfd, &fds);
|
||||||
|
if ((left = select(seqfd + 1, &fds, NULL, NULL, NULL)) < 0) {
|
||||||
|
printf("select error = %i (%s)\n", left, snd_strerror(left));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (left < 0) {
|
||||||
printf("alsa_sync error!:%s\n", snd_strerror(left));
|
printf("alsa_sync error!:%s\n", snd_strerror(left));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (verbose >= VERB_MUCH)
|
||||||
printf("alsa_sync got event. type=%d, flags=%d\n",
|
printf("alsa_sync got event. type=%d, flags=%d\n",
|
||||||
input_event->type, input_event->flags);
|
input_event->type, input_event->flags);
|
||||||
snd_seq_free_event(input_event);
|
snd_seq_free_event(input_event);
|
||||||
|
|
||||||
|
if (verbose >= VERB_MUCH)
|
||||||
printf("alsa_sync synced\n");
|
printf("alsa_sync synced\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* start timer */
|
/* print usage */
|
||||||
void alsa_start_timer(void)
|
static void usage(void)
|
||||||
{
|
{
|
||||||
snd_seq_event_t ev;
|
fprintf(stderr, "usage: playmidi1 [options] [file]\n");
|
||||||
|
fprintf(stderr, " options:\n");
|
||||||
ev.source.port = SND_SEQ_PORT_SYSTEM_TIMER;
|
fprintf(stderr, " -v: verbose mode\n");
|
||||||
ev.source.channel = 0;
|
fprintf(stderr, " -a queue:client:port : set destination address (default=%d:%d:%d)\n",
|
||||||
|
DEST_QUEUE_NUMBER, DEST_CLIENT_NUMBER, DEST_PORT_NUMBER);
|
||||||
ev.dest.queue = dest_queue;
|
|
||||||
ev.dest.client = SND_SEQ_CLIENT_SYSTEM; /* system */
|
|
||||||
ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; /* timer */
|
|
||||||
ev.dest.channel = 0; /* don't care */
|
|
||||||
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL;
|
|
||||||
ev.time.real.tv_sec = 0;
|
|
||||||
ev.time.real.tv_nsec = 0;
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_START;
|
|
||||||
|
|
||||||
write_ev_im(&ev);
|
|
||||||
usleep(0.1E6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stop timer */
|
/* parse destination address (-a option) */
|
||||||
void alsa_stop_timer(void)
|
void parse_address(char *arg, int *queuep, int *clientp, int *portp)
|
||||||
{
|
{
|
||||||
|
char *next;
|
||||||
|
|
||||||
snd_seq_event_t ev;
|
*queuep = atoi(arg);
|
||||||
|
if ((next = strchr(arg, ':')) != NULL) {
|
||||||
ev.source.port = 0;
|
*clientp = atoi(next + 1);
|
||||||
ev.source.channel = 0;
|
if ((next = strchr(next + 1, ':')) != NULL)
|
||||||
|
*portp = atoi(next + 1);
|
||||||
ev.dest.queue = dest_queue;
|
}
|
||||||
ev.dest.client = SND_SEQ_CLIENT_SYSTEM; /* system */
|
|
||||||
ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; /* timer */
|
|
||||||
ev.dest.channel = 0; /* don't care */
|
|
||||||
|
|
||||||
#ifdef USE_REALTIME
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
tick2time(&ev.time.real, Mf_currtime);
|
|
||||||
#else
|
|
||||||
ev.flags = SND_SEQ_TIME_STAMP_TICK | SND_SEQ_TIME_MODE_ABS;
|
|
||||||
ev.time.tick = Mf_currtime;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ev.type = SND_SEQ_EVENT_STOP;
|
|
||||||
|
|
||||||
write_ev_im(&ev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
|
@ -587,34 +496,54 @@ int main(int argc, char *argv[])
|
||||||
snd_seq_port_info_t src_port_info;
|
snd_seq_port_info_t src_port_info;
|
||||||
snd_seq_queue_client_t queue_info;
|
snd_seq_queue_client_t queue_info;
|
||||||
snd_seq_port_subscribe_t subscribe;
|
snd_seq_port_subscribe_t subscribe;
|
||||||
|
snd_seq_client_pool_t pool;
|
||||||
int tmp;
|
int tmp;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "a:v")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'v':
|
||||||
|
verbose++;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
parse_address(optarg, &dest_queue, &dest_client, &dest_port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose >= VERB_INFO) {
|
||||||
#ifdef USE_REALTIME
|
#ifdef USE_REALTIME
|
||||||
printf("ALSA MIDI Player, feeding events to real-time queue\n");
|
printf("ALSA MIDI Player, feeding events to real-time queue\n");
|
||||||
#else
|
#else
|
||||||
printf("ALSA MIDI Player, feeding events to song queue\n");
|
printf("ALSA MIDI Player, feeding events to song queue\n");
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* open sequencer device */
|
/* open sequencer device */
|
||||||
//Here we open the device read/write mode.
|
/* Here we open the device read/write mode. */
|
||||||
//Becase we write SND_SEQ_EVENT_ECHO to myself to sync.
|
/* Becase we write SND_SEQ_EVENT_ECHO to myself to sync. */
|
||||||
tmp = snd_seq_open(&seq_handle, SND_SEQ_OPEN);
|
tmp = snd_seq_open(&seq_handle, SND_SEQ_OPEN);
|
||||||
if (tmp < 0) {
|
if (tmp < 0) {
|
||||||
perror("open /dev/snd/seq");
|
perror("open /dev/snd/seq");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//tmp = snd_seq_block_mode (seq_handle, 0);
|
#ifdef USE_BLOCKING_MODE
|
||||||
tmp = snd_seq_block_mode(seq_handle, 1);
|
tmp = snd_seq_block_mode(seq_handle, 1);
|
||||||
if (tmp < 0)
|
#else
|
||||||
{
|
tmp = snd_seq_block_mode(seq_handle, 0);
|
||||||
|
#endif
|
||||||
|
if (tmp < 0) {
|
||||||
perror("block_mode");
|
perror("block_mode");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* set name */
|
/* set name */
|
||||||
//set event filter to recieve only echo event
|
/* set event filter to recieve only echo event */
|
||||||
memset(&inf, 0, sizeof(snd_seq_client_info_t));
|
memset(&inf, 0, sizeof(snd_seq_client_info_t));
|
||||||
inf.filter |= SND_SEQ_FILTER_USE_EVENT;
|
inf.filter |= SND_SEQ_FILTER_USE_EVENT;
|
||||||
memset(&inf.event_filter, 0, sizeof(inf.event_filter));
|
memset(&inf.event_filter, 0, sizeof(inf.event_filter));
|
||||||
|
|
@ -625,35 +554,30 @@ int main(int argc, char *argv[])
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//create port
|
/* create port */
|
||||||
memset(&src_port_info, 0, sizeof(snd_seq_port_info_t));
|
memset(&src_port_info, 0, sizeof(snd_seq_port_info_t));
|
||||||
src_port_info.capability = SND_SEQ_PORT_CAP_OUT | SND_SEQ_PORT_CAP_SUBSCRIPTION | SND_SEQ_PORT_CAP_IN;
|
src_port_info.capability = SND_SEQ_PORT_CAP_OUT | SND_SEQ_PORT_CAP_IN;
|
||||||
src_port_info.type = SND_SEQ_PORT_TYPE_MIDI_GENERIC;
|
src_port_info.type = SND_SEQ_PORT_TYPE_MIDI_GENERIC;
|
||||||
src_port_info.midi_channels = 16;
|
src_port_info.midi_channels = 16;
|
||||||
src_port_info.synth_voices = 0;
|
src_port_info.synth_voices = 0;
|
||||||
//src_port_info.use = 0;
|
|
||||||
src_port_info.kernel = NULL;
|
src_port_info.kernel = NULL;
|
||||||
tmp = snd_seq_create_port(seq_handle, &src_port_info);
|
tmp = snd_seq_create_port(seq_handle, &src_port_info);
|
||||||
if (tmp < 0)
|
if (tmp < 0) {
|
||||||
{
|
|
||||||
perror("creat port");
|
perror("creat port");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
source_port = src_port_info.port;
|
source_port = src_port_info.port;
|
||||||
|
|
||||||
//setup queue
|
/* setup queue */
|
||||||
queue_info.used = 1;
|
queue_info.used = 1;
|
||||||
queue_info.low = 1;//???
|
tmp = snd_seq_set_queue_client(seq_handle, dest_queue, &queue_info);
|
||||||
//queue_info.low = 0;
|
if (tmp < 0) {
|
||||||
queue_info.high = 500-100;//???
|
|
||||||
tmp = snd_seq_set_queue_client (seq_handle, dest_queue,
|
|
||||||
&queue_info);
|
|
||||||
if (tmp < 0)
|
|
||||||
{
|
|
||||||
perror("queue_client");
|
perror("queue_client");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
//setup subscriber
|
|
||||||
|
/* setup subscriber */
|
||||||
|
if (verbose >= VERB_INFO)
|
||||||
printf("debug subscribe src_port_info.client=%d\n",
|
printf("debug subscribe src_port_info.client=%d\n",
|
||||||
src_port_info.client);
|
src_port_info.client);
|
||||||
subscribe.sender.client = snd_seq_client_id(seq_handle);
|
subscribe.sender.client = snd_seq_client_id(seq_handle);
|
||||||
|
|
@ -665,15 +589,28 @@ int main(int argc, char *argv[])
|
||||||
subscribe.realtime = 1;
|
subscribe.realtime = 1;
|
||||||
subscribe.exclusive = 0;
|
subscribe.exclusive = 0;
|
||||||
tmp = snd_seq_subscribe_port(seq_handle, &subscribe);
|
tmp = snd_seq_subscribe_port(seq_handle, &subscribe);
|
||||||
if (tmp < 0)
|
if (tmp < 0) {
|
||||||
{
|
|
||||||
perror("subscribe");
|
perror("subscribe");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc > 1)
|
/* change pool size */
|
||||||
F = fopen(argv[1], "r");
|
pool.output_pool = WRITE_POOL_SIZE;
|
||||||
else
|
pool.input_pool = READ_POOL_SIZE;
|
||||||
|
pool.output_room = WRITE_POOL_SPACE;
|
||||||
|
tmp = snd_seq_set_client_pool(seq_handle, &pool);
|
||||||
|
if (tmp < 0) {
|
||||||
|
perror("pool");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < argc) {
|
||||||
|
F = fopen(argv[optind], "r");
|
||||||
|
if (F == NULL) {
|
||||||
|
fprintf(stderr, "playmidi1: can't open file %s\n", argv[optind]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else
|
||||||
F = stdin;
|
F = stdin;
|
||||||
|
|
||||||
Mf_header = do_header;
|
Mf_header = do_header;
|
||||||
|
|
@ -690,11 +627,6 @@ int main(int argc, char *argv[])
|
||||||
Mf_chanpressure = do_chanpressure;
|
Mf_chanpressure = do_chanpressure;
|
||||||
Mf_sysex = do_sysex;
|
Mf_sysex = do_sysex;
|
||||||
|
|
||||||
|
|
||||||
/* stop timer in case it was left running by a previous client */
|
|
||||||
alsa_stop_timer ();
|
|
||||||
alsa_start_timer ();
|
|
||||||
|
|
||||||
/* go.. go.. go.. */
|
/* go.. go.. go.. */
|
||||||
mfread();
|
mfread();
|
||||||
|
|
||||||
|
|
@ -703,9 +635,10 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
snd_seq_close(seq_handle);
|
snd_seq_close(seq_handle);
|
||||||
|
|
||||||
|
if (verbose >= VERB_INFO) {
|
||||||
printf("Stopping at %f s, tick %f\n",
|
printf("Stopping at %f s, tick %f\n",
|
||||||
tick2time_dbl(Mf_currtime + 1), (double) (Mf_currtime + 1));
|
tick2time_dbl(Mf_currtime + 1), (double) (Mf_currtime + 1));
|
||||||
|
}
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue