#include "grt.h"
#include <alsa/asoundlib.h>
#define my_package YdemosSelectrobeepSmusicSalsamidiYP
#define GOOFUNC(name) P YdemosSelectrobeepSmusicSalsamidiYP ## name
#define APPNAME "goo-midi"
#define hUnwrap(x) ((snd_seq_t *)YPlu(x))
#define hWrap(x) YPlb((P)x)
#define qUnwrap(x) ((int)YPiu(x))
#define qWrap(x) YPib((P)x)
int port_out_id, port_in_id;
GOOFUNC(midi_open_seq) ()
{
snd_seq_t *seq_handle;
if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
fprintf(stderr, "Error opening ALSA sequencer.\n");
exit(1);
}
snd_seq_set_client_name(seq_handle, APPNAME);
if ((port_out_id = snd_seq_create_simple_port(seq_handle, APPNAME,
SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
SND_SEQ_PORT_TYPE_APPLICATION)) < 0)
{
fprintf(stderr, "Error creating sequencer port.\n");
}
if ((port_in_id = snd_seq_create_simple_port(seq_handle, APPNAME,
SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
SND_SEQ_PORT_TYPE_APPLICATION)) < 0)
{
fprintf(stderr, "Error creating sequencer port.\n");
exit(1);
}
return(hWrap(seq_handle));
}
GOOFUNC(midi_get_tick) (P hSeq, P queue)
{
snd_seq_queue_status_t *status;
snd_seq_tick_time_t current_tick;
snd_seq_queue_status_malloc(&status);
snd_seq_get_queue_status(hUnwrap(hSeq), qUnwrap(queue), status);
current_tick = snd_seq_queue_status_get_tick_time(status);
snd_seq_queue_status_free(status);
return(YPib((P)current_tick));
}
GOOFUNC(midi_init_queue) (P hSeq)
{
return qWrap((P)snd_seq_alloc_queue(hUnwrap(hSeq)));
}
GOOFUNC(midi_clear_queue) (P hSeq, P queue)
{
snd_seq_remove_events_t *remove_ev;
snd_seq_remove_events_malloc(&remove_ev);
snd_seq_remove_events_set_queue(remove_ev, qUnwrap(queue));
snd_seq_remove_events_set_condition(remove_ev, SND_SEQ_REMOVE_OUTPUT | SND_SEQ_REMOVE_IGNORE_OFF);
snd_seq_remove_events(hUnwrap(hSeq), remove_ev);
snd_seq_remove_events_free(remove_ev);
return YPfalse;
}
GOOFUNC(midi_send_note) (P hSeq, P queue, P channel, P note, P velocity, P duration, P tick)
{
snd_seq_event_t ev;
snd_seq_ev_clear(&ev);
snd_seq_ev_set_note(&ev, YPiu(channel), YPiu(note), YPiu(velocity), YPiu(duration));
snd_seq_ev_schedule_tick(&ev, qUnwrap(queue), 0, YPiu(tick));
snd_seq_ev_set_source(&ev, port_out_id);
snd_seq_ev_set_subs(&ev);
snd_seq_event_output_direct(hUnwrap(hSeq), &ev);
return YPfalse;
}
GOOFUNC(midi_start_queue) (P hSeq, P queue)
{
snd_seq_start_queue(hUnwrap(hSeq), qUnwrap(queue), NULL);
return YPfalse;
}
GOOFUNC(midi_drain_output) (P hSeq)
{
snd_seq_drain_output(hUnwrap(hSeq));
return YPfalse;
}
GOOFUNC(midi_send_program_change) (P hSeq, P queue, P channel, P newpgm, P tick)
{
snd_seq_event_t ev;
snd_seq_ev_clear(&ev);
snd_seq_ev_set_pgmchange(&ev, YPiu(channel), YPiu(newpgm));
snd_seq_ev_schedule_tick(&ev, qUnwrap(queue), 0, YPiu(tick));
snd_seq_ev_set_source(&ev, port_out_id);
snd_seq_ev_set_subs(&ev);
snd_seq_event_output_direct(hUnwrap(hSeq), &ev);
return YPfalse;
}