summaryrefslogtreecommitdiffstats
path: root/alsa-lib/test/playmidi1.c
diff options
context:
space:
mode:
Diffstat (limited to 'alsa-lib/test/playmidi1.c')
-rw-r--r--alsa-lib/test/playmidi1.c617
1 files changed, 0 insertions, 617 deletions
diff --git a/alsa-lib/test/playmidi1.c b/alsa-lib/test/playmidi1.c
deleted file mode 100644
index a7f3a63..0000000
--- a/alsa-lib/test/playmidi1.c
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * MIDI file player for ALSA sequencer
- * (type 0 only!, the library that is used doesn't support merging of tracks)
- *
- * Copyright (c) 1998 by Frank van de Pol <F.K.W.van.de.Pol@inter.nl.net>
- *
- * Modified so that this uses alsa-lib
- * 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
- *
- * 19990827 Takashi Iwai <iwai@ww.uni-erlangen.de>
- * - use snd_seq_alloc_queue()
- *
- * 19990916 Takashi Iwai <iwai@ww.uni-erlangen.de>
- * - use middle-level sequencer routines and macros
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-
-#include "midifile.h" /* SMF library header */
-#include "midifile.c" /* SMF library code */
-
-#include "../include/asoundlib.h"
-
-/* send the real-time time stamps (instead of midi ticks) to the ALSA sequencer */
-static int use_realtime = 0;
-
-/* control the event buffering by using a blocking mode */
-static int use_blocking_mode = 1;
-
-/* default destination queue, client and port numbers */
-#define DEST_CLIENT_NUMBER 65
-#define DEST_PORT_NUMBER 0
-
-/* event pool size */
-#define WRITE_POOL_SIZE 200
-#define WRITE_POOL_SPACE 10
-#define READ_POOL_SIZE 10 /* we need to read the pool only for echoing */
-
-static FILE *F;
-static snd_seq_t *seq_handle = NULL;
-static int ppq = 96;
-static int slave_ppq = 96;
-
-static double local_secs = 0;
-static int local_ticks = 0;
-static int local_tempo = 500000;
-
-static int dest_queue = -1;
-static int shared_queue = 0;
-static int tick_offset = 0;
-static int dest_client = DEST_CLIENT_NUMBER;
-static int dest_port = DEST_PORT_NUMBER;
-static int my_port = 0;
-
-static int verbose = 0;
-static int slave = 0; /* allow external sync */
-
-#define VERB_INFO 1
-#define VERB_MUCH 2
-#define VERB_EVENT 3
-
-static void alsa_start_timer(void);
-static void alsa_stop_timer(void);
-static void wait_start(void);
-
-
-static inline double tick2time_dbl(int tick)
-{
- return local_secs + ((double) (tick - local_ticks) * (double) local_tempo * 1.0E-6 / (double) ppq);
-}
-
-static void tick2time(snd_seq_real_time_t * tm, int tick)
-{
- double secs = tick2time_dbl(tick);
- tm->tv_sec = secs;
- tm->tv_nsec = (secs - tm->tv_sec) * 1.0E9;
-}
-
-static void write_ev(snd_seq_event_t *ev)
-{
- int rc;
-
- if (use_blocking_mode) {
- rc = snd_seq_event_output(seq_handle, ev);
- if (rc < 0) {
- printf("written = %i (%s)\n", rc, snd_strerror(rc));
- exit(1);
- }
- return;
- }
- while ((rc = snd_seq_event_output(seq_handle, ev)) < 0) {
- int npfds = snd_seq_poll_descriptors_count(seq_handle, POLLOUT);
- struct pollfd *pfds = alloca(sizeof(*pfds) * npfds);
- snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLOUT);
- if ((rc = poll(pfds, npfds, -1)) < 0) {
- printf("poll error = %i (%s)\n", rc, snd_strerror(errno));
- exit(1);
- }
- }
-}
-
-/* read the byte */
-static int mygetc(void)
-{
- return getc(F);
-}
-
-/* print out the text */
-static void mytext(int type ATTRIBUTE_UNUSED, int leng, char *msg)
-{
- char *p;
- char *ep = msg + leng;
-
- if (verbose >= VERB_INFO) {
- for (p = msg; p < ep; p++)
- putchar(isprint(*p) ? *p : '?');
- putchar('\n');
- }
-}
-
-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);
- ppq = division;
-
- if (format != 0 || ntracks != 1) {
- printf("This player does not support merging of tracks.\n");
- if (! shared_queue)
- alsa_stop_timer();
- exit(1);
- }
- /* set the ppq */
- snd_seq_queue_tempo_alloca(&tempo);
- /* ppq must be set before starting the timer */
- if (snd_seq_get_queue_tempo(seq_handle, dest_queue, tempo) < 0) {
- perror("get_queue_tempo");
- exit(1);
- }
- if ((slave_ppq = snd_seq_queue_tempo_get_ppq(tempo)) != ppq) {
- snd_seq_queue_tempo_set_ppq(tempo, ppq);
- if (snd_seq_set_queue_tempo(seq_handle, dest_queue, tempo) < 0) {
- perror("set_queue_tempo");
- if (!slave && !shared_queue)
- exit(1);
- else
- printf("different PPQ %d in SMF from queue PPQ %d\n", ppq, slave_ppq);
- } else
- slave_ppq = ppq;
- if (verbose >= VERB_INFO)
- printf("ALSA Timer updated, PPQ = %d\n", snd_seq_queue_tempo_get_ppq(tempo));
- }
-
- /* start playing... */
- if (slave) {
- if (verbose >= VERB_INFO)
- printf("Wait till timer starts...\n");
- wait_start();
- if (verbose >= VERB_INFO)
- printf("Go!\n");
- } else if (shared_queue) {
- snd_seq_queue_status_t *stat;
- snd_seq_queue_status_alloca(&stat);
- snd_seq_get_queue_status(seq_handle, dest_queue, stat);
- tick_offset = snd_seq_queue_status_get_tick_time(stat);
- fprintf(stderr, "tick offset = %d\n", tick_offset);
- } else {
- alsa_start_timer();
- tick_offset = 0;
- }
-}
-
-/* fill the event time */
-static void set_event_time(snd_seq_event_t *ev, unsigned int currtime)
-{
- if (use_realtime) {
- snd_seq_real_time_t rtime;
- if (ppq != slave_ppq)
- currtime = (currtime * slave_ppq) / ppq;
- tick2time(&rtime, currtime);
- snd_seq_ev_schedule_real(ev, dest_queue, 0, &rtime);
- } else {
- if (ppq != slave_ppq)
- currtime = (currtime * slave_ppq) / ppq;
- currtime += tick_offset;
- snd_seq_ev_schedule_tick(ev, dest_queue, 0, currtime);
- }
-}
-
-/* fill the normal event header */
-static void set_event_header(snd_seq_event_t *ev)
-{
- snd_seq_ev_clear(ev);
- snd_seq_ev_set_dest(ev, dest_client, dest_port);
- snd_seq_ev_set_source(ev, my_port);
- set_event_time(ev, Mf_currtime);
-}
-
-/* start the timer */
-static void alsa_start_timer(void)
-{
- snd_seq_start_queue(seq_handle, dest_queue, NULL);
-}
-
-/* stop the timer */
-static void alsa_stop_timer(void)
-{
- snd_seq_event_t ev;
- set_event_header(&ev);
- snd_seq_stop_queue(seq_handle, dest_queue, &ev);
-}
-
-/* change the 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 the new tempo and timestamp of the tempo change */
- local_secs = tick2time_dbl(Mf_currtime);
- local_ticks = Mf_currtime;
- local_tempo = us;
-
- set_event_header(&ev);
- if (!slave)
- snd_seq_change_queue_tempo(seq_handle, dest_queue, us, &ev);
-}
-
-static void do_noteon(int chan, int pitch, int vol)
-{
- snd_seq_event_t ev;
-
- if (verbose >= VERB_EVENT)
- printf("%ld: NoteOn (%d) %d %d\n", Mf_currtime, chan, pitch, vol);
- set_event_header(&ev);
- snd_seq_ev_set_noteon(&ev, chan, pitch, vol);
- write_ev(&ev);
-}
-
-
-static void do_noteoff(int chan, int pitch, int vol)
-{
- snd_seq_event_t ev;
-
- if (verbose >= VERB_EVENT)
- printf("%ld: NoteOff (%d) %d %d\n", Mf_currtime, chan, pitch, vol);
- set_event_header(&ev);
- snd_seq_ev_set_noteoff(&ev, chan, pitch, vol);
- write_ev(&ev);
-}
-
-
-static void do_program(int chan, int program)
-{
- snd_seq_event_t ev;
-
- if (verbose >= VERB_EVENT)
- printf("%ld: Program (%d) %d\n", Mf_currtime, chan, program);
- set_event_header(&ev);
- snd_seq_ev_set_pgmchange(&ev, chan, program);
- write_ev(&ev);
-}
-
-
-static void do_parameter(int chan, int control, int value)
-{
- snd_seq_event_t ev;
-
- if (verbose >= VERB_EVENT)
- printf("%ld: Control (%d) %d %d\n", Mf_currtime, chan, control, value);
- set_event_header(&ev);
- snd_seq_ev_set_controller(&ev, chan, control, value);
- write_ev(&ev);
-}
-
-
-static void do_pitchbend(int chan, int lsb, int msb)
-{ /* !@#$% lsb & msb are in the wrong order in docs */
- snd_seq_event_t ev;
-
- if (verbose >= VERB_EVENT)
- printf("%ld: Pitchbend (%d) %d %d\n", Mf_currtime, chan, lsb, msb);
- set_event_header(&ev);
- snd_seq_ev_set_pitchbend(&ev, chan, (lsb + (msb << 7)) - 8192);
- write_ev(&ev);
-}
-
-static void do_pressure(int chan, int pitch, int pressure)
-{
- snd_seq_event_t ev;
-
- if (verbose >= VERB_EVENT)
- printf("%ld: KeyPress (%d) %d %d\n", Mf_currtime, chan, pitch, pressure);
- set_event_header(&ev);
- snd_seq_ev_set_keypress(&ev, chan, pitch, pressure);
- write_ev(&ev);
-}
-
-static void do_chanpressure(int chan, int pressure)
-{
- snd_seq_event_t ev;
-
- if (verbose >= VERB_EVENT)
- printf("%ld: ChanPress (%d) %d\n", Mf_currtime, chan, pressure);
- set_event_header(&ev);
- snd_seq_ev_set_chanpress(&ev, chan, pressure);
- write_ev(&ev);
-}
-
-static void do_sysex(int len, char *msg)
-{
- snd_seq_event_t ev;
-
- if (verbose >= VERB_MUCH) {
- int c;
- printf("%ld: Sysex, len=%d\n", Mf_currtime, len);
- for (c = 0; c < len; c++) {
- printf(" %02x", (unsigned char)msg[c]);
- if (c % 16 == 15)
- putchar('\n');
- }
- if (c % 16 != 15)
- putchar('\n');
- }
-
- set_event_header(&ev);
- snd_seq_ev_set_sysex(&ev, len, msg);
- write_ev(&ev);
-}
-
-static snd_seq_event_t *wait_for_event(void)
-{
- int left;
- snd_seq_event_t *input_event;
-
- if (use_blocking_mode) {
- /* read the event - blocked until any event is read */
- left = snd_seq_event_input(seq_handle, &input_event);
- } else {
- /* read the event - using select syscall */
- while ((left = snd_seq_event_input(seq_handle, &input_event)) >= 0 &&
- input_event == NULL) {
- int npfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN);
- struct pollfd *pfds = alloca(sizeof(*pfds) * npfds);
- snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLIN);
- if ((left = poll(pfds, npfds, -1)) < 0) {
- printf("poll error = %i (%s)\n", errno, snd_strerror(errno));
- exit(1);
- }
- }
- }
-
- if (left < 0) {
- printf("alsa_sync error!:%s\n", snd_strerror(left));
- return NULL;
- }
-
- return input_event;
-}
-
-/* synchronize to the end of the event */
-static void alsa_sync(void)
-{
- /* send the echo event to the self client. */
- if (verbose >= VERB_MUCH)
- printf("alsa_sync syncing...\n");
- /* dump the buffer */
- snd_seq_drain_output(seq_handle);
- snd_seq_sync_output_queue(seq_handle);
- if (verbose >= VERB_MUCH)
- printf("alsa_sync synced\n");
- sleep(1); /* give a time for note releasing.. */
-}
-
-
-/* wait for the start of the queue */
-static void wait_start(void)
-{
- snd_seq_event_t *input_event;
-
- /* wait for the start event from the system timer */
- for (;;) {
- input_event = wait_for_event();
- if (input_event) {
- if (verbose >= VERB_MUCH)
- printf("wait_start got event. type=%d, flags=%d\n",
- input_event->type, input_event->flags);
- if (input_event->type == SND_SEQ_EVENT_START &&
- input_event->data.queue.queue == dest_queue) {
- snd_seq_free_event(input_event);
- break;
- }
- snd_seq_free_event(input_event);
- }
- }
- if (verbose >= VERB_MUCH)
- printf("start received\n");
-}
-
-
-/* print the usage */
-static void usage(void)
-{
- fprintf(stderr, "usage: playmidi1 [options] [file]\n");
- fprintf(stderr, " options:\n");
- fprintf(stderr, " -v: verbose mode\n");
- fprintf(stderr, " -a client:port : set destination address (default=%d:%d)\n",
- DEST_CLIENT_NUMBER, DEST_PORT_NUMBER);
- fprintf(stderr, " -q queue: use the specified queue\n");
- fprintf(stderr, " -s queue: slave mode (allow external clock synchronization)\n");
- fprintf(stderr, " -r : play on real-time mode\n");
- fprintf(stderr, " -b : play on non-blocking mode\n");
-}
-
-int main(int argc, char *argv[])
-{
- int tmp;
- int c;
- snd_seq_addr_t dest_addr;
- const char *addr = "65:0";
-
- while ((c = getopt(argc, argv, "s:a:p:q:vrb")) != -1) {
- switch (c) {
- case 'v':
- verbose++;
- break;
- case 'a':
- case 'p':
- addr = optarg;
- break;
- case 'q':
- dest_queue = atoi(optarg);
- if (dest_queue < 0) {
- fprintf(stderr, "invalid queue number %d\n", dest_queue);
- exit(1);
- }
- break;
- case 's':
- slave = 1;
- dest_queue = atoi(optarg);
- if (dest_queue < 0) {
- fprintf(stderr, "invalid queue number %d\n", dest_queue);
- exit(1);
- }
- break;
- case 'r':
- use_realtime = 1;
- break;
- case 'b':
- use_blocking_mode = 0;
- break;
- default:
- usage();
- exit(1);
- }
- }
-
- if (verbose >= VERB_INFO) {
- if (use_realtime)
- printf("ALSA MIDI Player, feeding events to real-time queue\n");
- else
- printf("ALSA MIDI Player, feeding events to song queue\n");
- }
-
- /* open the sequencer device */
- /* Here we open the device in read/write for slave mode. */
- tmp = snd_seq_open(&seq_handle, "hw", slave ? SND_SEQ_OPEN_DUPLEX : SND_SEQ_OPEN_OUTPUT, 0);
- if (tmp < 0) {
- perror("open /dev/snd/seq");
- exit(1);
- }
-
- tmp = snd_seq_nonblock(seq_handle, !use_blocking_mode);
- if (tmp < 0) {
- perror("block_mode");
- exit(1);
- }
-
- /* set the name */
- /* set the event filter to receive only the echo event */
- /* if running in slave mode, also listen for a START event */
- if (slave)
- snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_START);
- snd_seq_set_client_name(seq_handle, "MIDI file player");
-
- /* create the port */
- my_port = snd_seq_create_simple_port(seq_handle, "Port 0",
- SND_SEQ_PORT_CAP_WRITE |
- SND_SEQ_PORT_CAP_READ,
- SND_SEQ_PORT_TYPE_MIDI_GENERIC);
- if (my_port < 0) {
- perror("create port");
- exit(1);
- }
-
- if (snd_seq_parse_address(seq_handle, &dest_addr, addr) < 0) {
- perror("invalid destination address");
- exit(1);
- }
- dest_client = dest_addr.client;
- dest_port = dest_addr.port;
-
- /* set the queue */
- if (dest_queue >= 0) {
- shared_queue = 1;
- if (snd_seq_set_queue_usage(seq_handle, dest_queue, 1) < 0) {
- perror("use queue");
- exit(1);
- }
- } else {
- shared_queue = 0;
- dest_queue = snd_seq_alloc_queue(seq_handle);
- if (dest_queue < 0) {
- perror("alloc queue");
- exit(1);
- }
- }
-
- /* set the subscriber */
- tmp = snd_seq_connect_to(seq_handle, my_port, dest_client, dest_port);
- if (tmp < 0) {
- perror("subscribe");
- exit(1);
- }
-
- /* subscribe for the timer START event */
- if (slave) {
- tmp = snd_seq_connect_from(seq_handle, my_port,
- SND_SEQ_CLIENT_SYSTEM,
- dest_queue + 16 /*snd_seq_queue_sync_port(dest_queue)*/);
- if (tmp < 0) {
- perror("subscribe");
- exit(1);
- }
- }
-
- /* change the pool size */
- if (snd_seq_set_client_pool_output(seq_handle, WRITE_POOL_SIZE) < 0 ||
- snd_seq_set_client_pool_input(seq_handle, READ_POOL_SIZE) < 0 ||
- snd_seq_set_client_pool_output_room(seq_handle, WRITE_POOL_SPACE) < 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;
-
- Mf_header = do_header;
- Mf_tempo = do_tempo;
- Mf_getc = mygetc;
- Mf_text = mytext;
-
- Mf_noteon = do_noteon;
- Mf_noteoff = do_noteoff;
- Mf_program = do_program;
- Mf_parameter = do_parameter;
- Mf_pitchbend = do_pitchbend;
- Mf_pressure = do_pressure;
- Mf_chanpressure = do_chanpressure;
- Mf_sysex = do_sysex;
-
- /* go.. go.. go.. */
- mfread();
-
- alsa_sync();
- if (! shared_queue)
- alsa_stop_timer();
-
- snd_seq_close(seq_handle);
-
- if (verbose >= VERB_INFO) {
- printf("Stopping at %f s, tick %f\n",
- tick2time_dbl(Mf_currtime + 1), (double) (Mf_currtime + 1));
- }
-
- exit(0);
-}