1d5ac70f0Sopenharmony_ci/* 2d5ac70f0Sopenharmony_ci * MIDI file player for ALSA sequencer 3d5ac70f0Sopenharmony_ci * (type 0 only!, the library that is used doesn't support merging of tracks) 4d5ac70f0Sopenharmony_ci * 5d5ac70f0Sopenharmony_ci * Copyright (c) 1998 by Frank van de Pol <F.K.W.van.de.Pol@inter.nl.net> 6d5ac70f0Sopenharmony_ci * 7d5ac70f0Sopenharmony_ci * Modified so that this uses alsa-lib 8d5ac70f0Sopenharmony_ci * 1999 Jan. by Isaku Yamahata <yamahata@kusm.kyoto-u.ac.jp> 9d5ac70f0Sopenharmony_ci * 10d5ac70f0Sopenharmony_ci * 19990604 Takashi Iwai <iwai@ww.uni-erlangen.de> 11d5ac70f0Sopenharmony_ci * - use blocking mode 12d5ac70f0Sopenharmony_ci * - fix tempo event bug 13d5ac70f0Sopenharmony_ci * - add command line options 14d5ac70f0Sopenharmony_ci * 15d5ac70f0Sopenharmony_ci * 19990827 Takashi Iwai <iwai@ww.uni-erlangen.de> 16d5ac70f0Sopenharmony_ci * - use snd_seq_alloc_queue() 17d5ac70f0Sopenharmony_ci * 18d5ac70f0Sopenharmony_ci * 19990916 Takashi Iwai <iwai@ww.uni-erlangen.de> 19d5ac70f0Sopenharmony_ci * - use middle-level sequencer routines and macros 20d5ac70f0Sopenharmony_ci * 21d5ac70f0Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 22d5ac70f0Sopenharmony_ci * it under the terms of the GNU General Public License as published by 23d5ac70f0Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 24d5ac70f0Sopenharmony_ci * (at your option) any later version. 25d5ac70f0Sopenharmony_ci * 26d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 27d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 28d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29d5ac70f0Sopenharmony_ci * GNU General Public License for more details. 30d5ac70f0Sopenharmony_ci * 31d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU General Public License 32d5ac70f0Sopenharmony_ci * along with this program; if not, write to the Free Software 33d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 34d5ac70f0Sopenharmony_ci * 35d5ac70f0Sopenharmony_ci */ 36d5ac70f0Sopenharmony_ci 37d5ac70f0Sopenharmony_ci#include "config.h" 38d5ac70f0Sopenharmony_ci 39d5ac70f0Sopenharmony_ci#include <stdio.h> 40d5ac70f0Sopenharmony_ci#include <ctype.h> 41d5ac70f0Sopenharmony_ci#include <fcntl.h> 42d5ac70f0Sopenharmony_ci#include <stdlib.h> 43d5ac70f0Sopenharmony_ci#include <sys/ioctl.h> 44d5ac70f0Sopenharmony_ci#include <unistd.h> 45d5ac70f0Sopenharmony_ci#include <errno.h> 46d5ac70f0Sopenharmony_ci#include <string.h> 47d5ac70f0Sopenharmony_ci 48d5ac70f0Sopenharmony_ci#include "midifile.h" /* SMF library header */ 49d5ac70f0Sopenharmony_ci#include "midifile.c" /* SMF library code */ 50d5ac70f0Sopenharmony_ci 51d5ac70f0Sopenharmony_ci#include "../include/asoundlib.h" 52d5ac70f0Sopenharmony_ci 53d5ac70f0Sopenharmony_ci/* send the real-time time stamps (instead of midi ticks) to the ALSA sequencer */ 54d5ac70f0Sopenharmony_cistatic int use_realtime = 0; 55d5ac70f0Sopenharmony_ci 56d5ac70f0Sopenharmony_ci/* control the event buffering by using a blocking mode */ 57d5ac70f0Sopenharmony_cistatic int use_blocking_mode = 1; 58d5ac70f0Sopenharmony_ci 59d5ac70f0Sopenharmony_ci/* default destination queue, client and port numbers */ 60d5ac70f0Sopenharmony_ci#define DEST_CLIENT_NUMBER 65 61d5ac70f0Sopenharmony_ci#define DEST_PORT_NUMBER 0 62d5ac70f0Sopenharmony_ci 63d5ac70f0Sopenharmony_ci/* event pool size */ 64d5ac70f0Sopenharmony_ci#define WRITE_POOL_SIZE 200 65d5ac70f0Sopenharmony_ci#define WRITE_POOL_SPACE 10 66d5ac70f0Sopenharmony_ci#define READ_POOL_SIZE 10 /* we need to read the pool only for echoing */ 67d5ac70f0Sopenharmony_ci 68d5ac70f0Sopenharmony_cistatic FILE *F; 69d5ac70f0Sopenharmony_cistatic snd_seq_t *seq_handle = NULL; 70d5ac70f0Sopenharmony_cistatic int ppq = 96; 71d5ac70f0Sopenharmony_cistatic int slave_ppq = 96; 72d5ac70f0Sopenharmony_ci 73d5ac70f0Sopenharmony_cistatic double local_secs = 0; 74d5ac70f0Sopenharmony_cistatic int local_ticks = 0; 75d5ac70f0Sopenharmony_cistatic int local_tempo = 500000; 76d5ac70f0Sopenharmony_ci 77d5ac70f0Sopenharmony_cistatic int dest_queue = -1; 78d5ac70f0Sopenharmony_cistatic int shared_queue = 0; 79d5ac70f0Sopenharmony_cistatic int tick_offset = 0; 80d5ac70f0Sopenharmony_cistatic int dest_client = DEST_CLIENT_NUMBER; 81d5ac70f0Sopenharmony_cistatic int dest_port = DEST_PORT_NUMBER; 82d5ac70f0Sopenharmony_cistatic int my_port = 0; 83d5ac70f0Sopenharmony_ci 84d5ac70f0Sopenharmony_cistatic int verbose = 0; 85d5ac70f0Sopenharmony_cistatic int slave = 0; /* allow external sync */ 86d5ac70f0Sopenharmony_ci 87d5ac70f0Sopenharmony_ci#define VERB_INFO 1 88d5ac70f0Sopenharmony_ci#define VERB_MUCH 2 89d5ac70f0Sopenharmony_ci#define VERB_EVENT 3 90d5ac70f0Sopenharmony_ci 91d5ac70f0Sopenharmony_cistatic void alsa_start_timer(void); 92d5ac70f0Sopenharmony_cistatic void alsa_stop_timer(void); 93d5ac70f0Sopenharmony_cistatic void wait_start(void); 94d5ac70f0Sopenharmony_ci 95d5ac70f0Sopenharmony_ci 96d5ac70f0Sopenharmony_cistatic inline double tick2time_dbl(int tick) 97d5ac70f0Sopenharmony_ci{ 98d5ac70f0Sopenharmony_ci return local_secs + ((double) (tick - local_ticks) * (double) local_tempo * 1.0E-6 / (double) ppq); 99d5ac70f0Sopenharmony_ci} 100d5ac70f0Sopenharmony_ci 101d5ac70f0Sopenharmony_cistatic void tick2time(snd_seq_real_time_t * tm, int tick) 102d5ac70f0Sopenharmony_ci{ 103d5ac70f0Sopenharmony_ci double secs = tick2time_dbl(tick); 104d5ac70f0Sopenharmony_ci tm->tv_sec = secs; 105d5ac70f0Sopenharmony_ci tm->tv_nsec = (secs - tm->tv_sec) * 1.0E9; 106d5ac70f0Sopenharmony_ci} 107d5ac70f0Sopenharmony_ci 108d5ac70f0Sopenharmony_cistatic void write_ev(snd_seq_event_t *ev) 109d5ac70f0Sopenharmony_ci{ 110d5ac70f0Sopenharmony_ci int rc; 111d5ac70f0Sopenharmony_ci 112d5ac70f0Sopenharmony_ci if (use_blocking_mode) { 113d5ac70f0Sopenharmony_ci rc = snd_seq_event_output(seq_handle, ev); 114d5ac70f0Sopenharmony_ci if (rc < 0) { 115d5ac70f0Sopenharmony_ci printf("written = %i (%s)\n", rc, snd_strerror(rc)); 116d5ac70f0Sopenharmony_ci exit(1); 117d5ac70f0Sopenharmony_ci } 118d5ac70f0Sopenharmony_ci return; 119d5ac70f0Sopenharmony_ci } 120d5ac70f0Sopenharmony_ci while ((rc = snd_seq_event_output(seq_handle, ev)) < 0) { 121d5ac70f0Sopenharmony_ci int npfds = snd_seq_poll_descriptors_count(seq_handle, POLLOUT); 122d5ac70f0Sopenharmony_ci struct pollfd *pfds = alloca(sizeof(*pfds) * npfds); 123d5ac70f0Sopenharmony_ci snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLOUT); 124d5ac70f0Sopenharmony_ci if ((rc = poll(pfds, npfds, -1)) < 0) { 125d5ac70f0Sopenharmony_ci printf("poll error = %i (%s)\n", rc, snd_strerror(errno)); 126d5ac70f0Sopenharmony_ci exit(1); 127d5ac70f0Sopenharmony_ci } 128d5ac70f0Sopenharmony_ci } 129d5ac70f0Sopenharmony_ci} 130d5ac70f0Sopenharmony_ci 131d5ac70f0Sopenharmony_ci/* read the byte */ 132d5ac70f0Sopenharmony_cistatic int mygetc(void) 133d5ac70f0Sopenharmony_ci{ 134d5ac70f0Sopenharmony_ci return getc(F); 135d5ac70f0Sopenharmony_ci} 136d5ac70f0Sopenharmony_ci 137d5ac70f0Sopenharmony_ci/* print out the text */ 138d5ac70f0Sopenharmony_cistatic void mytext(int type ATTRIBUTE_UNUSED, int leng, char *msg) 139d5ac70f0Sopenharmony_ci{ 140d5ac70f0Sopenharmony_ci char *p; 141d5ac70f0Sopenharmony_ci char *ep = msg + leng; 142d5ac70f0Sopenharmony_ci 143d5ac70f0Sopenharmony_ci if (verbose >= VERB_INFO) { 144d5ac70f0Sopenharmony_ci for (p = msg; p < ep; p++) 145d5ac70f0Sopenharmony_ci putchar(isprint(*p) ? *p : '?'); 146d5ac70f0Sopenharmony_ci putchar('\n'); 147d5ac70f0Sopenharmony_ci } 148d5ac70f0Sopenharmony_ci} 149d5ac70f0Sopenharmony_ci 150d5ac70f0Sopenharmony_cistatic void do_header(int format, int ntracks, int division) 151d5ac70f0Sopenharmony_ci{ 152d5ac70f0Sopenharmony_ci snd_seq_queue_tempo_t *tempo; 153d5ac70f0Sopenharmony_ci 154d5ac70f0Sopenharmony_ci if (verbose >= VERB_INFO) 155d5ac70f0Sopenharmony_ci printf("smf format %d, %d tracks, %d ppq\n", format, ntracks, division); 156d5ac70f0Sopenharmony_ci ppq = division; 157d5ac70f0Sopenharmony_ci 158d5ac70f0Sopenharmony_ci if (format != 0 || ntracks != 1) { 159d5ac70f0Sopenharmony_ci printf("This player does not support merging of tracks.\n"); 160d5ac70f0Sopenharmony_ci if (! shared_queue) 161d5ac70f0Sopenharmony_ci alsa_stop_timer(); 162d5ac70f0Sopenharmony_ci exit(1); 163d5ac70f0Sopenharmony_ci } 164d5ac70f0Sopenharmony_ci /* set the ppq */ 165d5ac70f0Sopenharmony_ci snd_seq_queue_tempo_alloca(&tempo); 166d5ac70f0Sopenharmony_ci /* ppq must be set before starting the timer */ 167d5ac70f0Sopenharmony_ci if (snd_seq_get_queue_tempo(seq_handle, dest_queue, tempo) < 0) { 168d5ac70f0Sopenharmony_ci perror("get_queue_tempo"); 169d5ac70f0Sopenharmony_ci exit(1); 170d5ac70f0Sopenharmony_ci } 171d5ac70f0Sopenharmony_ci if ((slave_ppq = snd_seq_queue_tempo_get_ppq(tempo)) != ppq) { 172d5ac70f0Sopenharmony_ci snd_seq_queue_tempo_set_ppq(tempo, ppq); 173d5ac70f0Sopenharmony_ci if (snd_seq_set_queue_tempo(seq_handle, dest_queue, tempo) < 0) { 174d5ac70f0Sopenharmony_ci perror("set_queue_tempo"); 175d5ac70f0Sopenharmony_ci if (!slave && !shared_queue) 176d5ac70f0Sopenharmony_ci exit(1); 177d5ac70f0Sopenharmony_ci else 178d5ac70f0Sopenharmony_ci printf("different PPQ %d in SMF from queue PPQ %d\n", ppq, slave_ppq); 179d5ac70f0Sopenharmony_ci } else 180d5ac70f0Sopenharmony_ci slave_ppq = ppq; 181d5ac70f0Sopenharmony_ci if (verbose >= VERB_INFO) 182d5ac70f0Sopenharmony_ci printf("ALSA Timer updated, PPQ = %d\n", snd_seq_queue_tempo_get_ppq(tempo)); 183d5ac70f0Sopenharmony_ci } 184d5ac70f0Sopenharmony_ci 185d5ac70f0Sopenharmony_ci /* start playing... */ 186d5ac70f0Sopenharmony_ci if (slave) { 187d5ac70f0Sopenharmony_ci if (verbose >= VERB_INFO) 188d5ac70f0Sopenharmony_ci printf("Wait till timer starts...\n"); 189d5ac70f0Sopenharmony_ci wait_start(); 190d5ac70f0Sopenharmony_ci if (verbose >= VERB_INFO) 191d5ac70f0Sopenharmony_ci printf("Go!\n"); 192d5ac70f0Sopenharmony_ci } else if (shared_queue) { 193d5ac70f0Sopenharmony_ci snd_seq_queue_status_t *stat; 194d5ac70f0Sopenharmony_ci snd_seq_queue_status_alloca(&stat); 195d5ac70f0Sopenharmony_ci snd_seq_get_queue_status(seq_handle, dest_queue, stat); 196d5ac70f0Sopenharmony_ci tick_offset = snd_seq_queue_status_get_tick_time(stat); 197d5ac70f0Sopenharmony_ci fprintf(stderr, "tick offset = %d\n", tick_offset); 198d5ac70f0Sopenharmony_ci } else { 199d5ac70f0Sopenharmony_ci alsa_start_timer(); 200d5ac70f0Sopenharmony_ci tick_offset = 0; 201d5ac70f0Sopenharmony_ci } 202d5ac70f0Sopenharmony_ci} 203d5ac70f0Sopenharmony_ci 204d5ac70f0Sopenharmony_ci/* fill the event time */ 205d5ac70f0Sopenharmony_cistatic void set_event_time(snd_seq_event_t *ev, unsigned int currtime) 206d5ac70f0Sopenharmony_ci{ 207d5ac70f0Sopenharmony_ci if (use_realtime) { 208d5ac70f0Sopenharmony_ci snd_seq_real_time_t rtime; 209d5ac70f0Sopenharmony_ci if (ppq != slave_ppq) 210d5ac70f0Sopenharmony_ci currtime = (currtime * slave_ppq) / ppq; 211d5ac70f0Sopenharmony_ci tick2time(&rtime, currtime); 212d5ac70f0Sopenharmony_ci snd_seq_ev_schedule_real(ev, dest_queue, 0, &rtime); 213d5ac70f0Sopenharmony_ci } else { 214d5ac70f0Sopenharmony_ci if (ppq != slave_ppq) 215d5ac70f0Sopenharmony_ci currtime = (currtime * slave_ppq) / ppq; 216d5ac70f0Sopenharmony_ci currtime += tick_offset; 217d5ac70f0Sopenharmony_ci snd_seq_ev_schedule_tick(ev, dest_queue, 0, currtime); 218d5ac70f0Sopenharmony_ci } 219d5ac70f0Sopenharmony_ci} 220d5ac70f0Sopenharmony_ci 221d5ac70f0Sopenharmony_ci/* fill the normal event header */ 222d5ac70f0Sopenharmony_cistatic void set_event_header(snd_seq_event_t *ev) 223d5ac70f0Sopenharmony_ci{ 224d5ac70f0Sopenharmony_ci snd_seq_ev_clear(ev); 225d5ac70f0Sopenharmony_ci snd_seq_ev_set_dest(ev, dest_client, dest_port); 226d5ac70f0Sopenharmony_ci snd_seq_ev_set_source(ev, my_port); 227d5ac70f0Sopenharmony_ci set_event_time(ev, Mf_currtime); 228d5ac70f0Sopenharmony_ci} 229d5ac70f0Sopenharmony_ci 230d5ac70f0Sopenharmony_ci/* start the timer */ 231d5ac70f0Sopenharmony_cistatic void alsa_start_timer(void) 232d5ac70f0Sopenharmony_ci{ 233d5ac70f0Sopenharmony_ci snd_seq_start_queue(seq_handle, dest_queue, NULL); 234d5ac70f0Sopenharmony_ci} 235d5ac70f0Sopenharmony_ci 236d5ac70f0Sopenharmony_ci/* stop the timer */ 237d5ac70f0Sopenharmony_cistatic void alsa_stop_timer(void) 238d5ac70f0Sopenharmony_ci{ 239d5ac70f0Sopenharmony_ci snd_seq_event_t ev; 240d5ac70f0Sopenharmony_ci set_event_header(&ev); 241d5ac70f0Sopenharmony_ci snd_seq_stop_queue(seq_handle, dest_queue, &ev); 242d5ac70f0Sopenharmony_ci} 243d5ac70f0Sopenharmony_ci 244d5ac70f0Sopenharmony_ci/* change the tempo */ 245d5ac70f0Sopenharmony_cistatic void do_tempo(int us) 246d5ac70f0Sopenharmony_ci{ 247d5ac70f0Sopenharmony_ci snd_seq_event_t ev; 248d5ac70f0Sopenharmony_ci 249d5ac70f0Sopenharmony_ci if (verbose >= VERB_MUCH) { 250d5ac70f0Sopenharmony_ci double bpm; 251d5ac70f0Sopenharmony_ci bpm = 60.0E6 / (double) us; 252d5ac70f0Sopenharmony_ci printf("Tempo %d us/beat, %.2f bpm\n", us, bpm); 253d5ac70f0Sopenharmony_ci } 254d5ac70f0Sopenharmony_ci 255d5ac70f0Sopenharmony_ci /* store the new tempo and timestamp of the tempo change */ 256d5ac70f0Sopenharmony_ci local_secs = tick2time_dbl(Mf_currtime); 257d5ac70f0Sopenharmony_ci local_ticks = Mf_currtime; 258d5ac70f0Sopenharmony_ci local_tempo = us; 259d5ac70f0Sopenharmony_ci 260d5ac70f0Sopenharmony_ci set_event_header(&ev); 261d5ac70f0Sopenharmony_ci if (!slave) 262d5ac70f0Sopenharmony_ci snd_seq_change_queue_tempo(seq_handle, dest_queue, us, &ev); 263d5ac70f0Sopenharmony_ci} 264d5ac70f0Sopenharmony_ci 265d5ac70f0Sopenharmony_cistatic void do_noteon(int chan, int pitch, int vol) 266d5ac70f0Sopenharmony_ci{ 267d5ac70f0Sopenharmony_ci snd_seq_event_t ev; 268d5ac70f0Sopenharmony_ci 269d5ac70f0Sopenharmony_ci if (verbose >= VERB_EVENT) 270d5ac70f0Sopenharmony_ci printf("%lu: NoteOn (%d) %d %d\n", Mf_currtime, chan, pitch, vol); 271d5ac70f0Sopenharmony_ci set_event_header(&ev); 272d5ac70f0Sopenharmony_ci snd_seq_ev_set_noteon(&ev, chan, pitch, vol); 273d5ac70f0Sopenharmony_ci write_ev(&ev); 274d5ac70f0Sopenharmony_ci} 275d5ac70f0Sopenharmony_ci 276d5ac70f0Sopenharmony_ci 277d5ac70f0Sopenharmony_cistatic void do_noteoff(int chan, int pitch, int vol) 278d5ac70f0Sopenharmony_ci{ 279d5ac70f0Sopenharmony_ci snd_seq_event_t ev; 280d5ac70f0Sopenharmony_ci 281d5ac70f0Sopenharmony_ci if (verbose >= VERB_EVENT) 282d5ac70f0Sopenharmony_ci printf("%lu: NoteOff (%d) %d %d\n", Mf_currtime, chan, pitch, vol); 283d5ac70f0Sopenharmony_ci set_event_header(&ev); 284d5ac70f0Sopenharmony_ci snd_seq_ev_set_noteoff(&ev, chan, pitch, vol); 285d5ac70f0Sopenharmony_ci write_ev(&ev); 286d5ac70f0Sopenharmony_ci} 287d5ac70f0Sopenharmony_ci 288d5ac70f0Sopenharmony_ci 289d5ac70f0Sopenharmony_cistatic void do_program(int chan, int program) 290d5ac70f0Sopenharmony_ci{ 291d5ac70f0Sopenharmony_ci snd_seq_event_t ev; 292d5ac70f0Sopenharmony_ci 293d5ac70f0Sopenharmony_ci if (verbose >= VERB_EVENT) 294d5ac70f0Sopenharmony_ci printf("%lu: Program (%d) %d\n", Mf_currtime, chan, program); 295d5ac70f0Sopenharmony_ci set_event_header(&ev); 296d5ac70f0Sopenharmony_ci snd_seq_ev_set_pgmchange(&ev, chan, program); 297d5ac70f0Sopenharmony_ci write_ev(&ev); 298d5ac70f0Sopenharmony_ci} 299d5ac70f0Sopenharmony_ci 300d5ac70f0Sopenharmony_ci 301d5ac70f0Sopenharmony_cistatic void do_parameter(int chan, int control, int value) 302d5ac70f0Sopenharmony_ci{ 303d5ac70f0Sopenharmony_ci snd_seq_event_t ev; 304d5ac70f0Sopenharmony_ci 305d5ac70f0Sopenharmony_ci if (verbose >= VERB_EVENT) 306d5ac70f0Sopenharmony_ci printf("%lu: Control (%d) %d %d\n", Mf_currtime, chan, control, value); 307d5ac70f0Sopenharmony_ci set_event_header(&ev); 308d5ac70f0Sopenharmony_ci snd_seq_ev_set_controller(&ev, chan, control, value); 309d5ac70f0Sopenharmony_ci write_ev(&ev); 310d5ac70f0Sopenharmony_ci} 311d5ac70f0Sopenharmony_ci 312d5ac70f0Sopenharmony_ci 313d5ac70f0Sopenharmony_cistatic void do_pitchbend(int chan, int lsb, int msb) 314d5ac70f0Sopenharmony_ci{ /* !@#$% lsb & msb are in the wrong order in docs */ 315d5ac70f0Sopenharmony_ci snd_seq_event_t ev; 316d5ac70f0Sopenharmony_ci 317d5ac70f0Sopenharmony_ci if (verbose >= VERB_EVENT) 318d5ac70f0Sopenharmony_ci printf("%lu: Pitchbend (%d) %d %d\n", Mf_currtime, chan, lsb, msb); 319d5ac70f0Sopenharmony_ci set_event_header(&ev); 320d5ac70f0Sopenharmony_ci snd_seq_ev_set_pitchbend(&ev, chan, (lsb + (msb << 7)) - 8192); 321d5ac70f0Sopenharmony_ci write_ev(&ev); 322d5ac70f0Sopenharmony_ci} 323d5ac70f0Sopenharmony_ci 324d5ac70f0Sopenharmony_cistatic void do_pressure(int chan, int pitch, int pressure) 325d5ac70f0Sopenharmony_ci{ 326d5ac70f0Sopenharmony_ci snd_seq_event_t ev; 327d5ac70f0Sopenharmony_ci 328d5ac70f0Sopenharmony_ci if (verbose >= VERB_EVENT) 329d5ac70f0Sopenharmony_ci printf("%lu: KeyPress (%d) %d %d\n", Mf_currtime, chan, pitch, pressure); 330d5ac70f0Sopenharmony_ci set_event_header(&ev); 331d5ac70f0Sopenharmony_ci snd_seq_ev_set_keypress(&ev, chan, pitch, pressure); 332d5ac70f0Sopenharmony_ci write_ev(&ev); 333d5ac70f0Sopenharmony_ci} 334d5ac70f0Sopenharmony_ci 335d5ac70f0Sopenharmony_cistatic void do_chanpressure(int chan, int pressure) 336d5ac70f0Sopenharmony_ci{ 337d5ac70f0Sopenharmony_ci snd_seq_event_t ev; 338d5ac70f0Sopenharmony_ci 339d5ac70f0Sopenharmony_ci if (verbose >= VERB_EVENT) 340d5ac70f0Sopenharmony_ci printf("%lu: ChanPress (%d) %d\n", Mf_currtime, chan, pressure); 341d5ac70f0Sopenharmony_ci set_event_header(&ev); 342d5ac70f0Sopenharmony_ci snd_seq_ev_set_chanpress(&ev, chan, pressure); 343d5ac70f0Sopenharmony_ci write_ev(&ev); 344d5ac70f0Sopenharmony_ci} 345d5ac70f0Sopenharmony_ci 346d5ac70f0Sopenharmony_cistatic void do_sysex(int len, char *msg) 347d5ac70f0Sopenharmony_ci{ 348d5ac70f0Sopenharmony_ci snd_seq_event_t ev; 349d5ac70f0Sopenharmony_ci 350d5ac70f0Sopenharmony_ci if (verbose >= VERB_MUCH) { 351d5ac70f0Sopenharmony_ci int c; 352d5ac70f0Sopenharmony_ci printf("%lu: Sysex, len=%d\n", Mf_currtime, len); 353d5ac70f0Sopenharmony_ci for (c = 0; c < len; c++) { 354d5ac70f0Sopenharmony_ci printf(" %02x", (unsigned char)msg[c]); 355d5ac70f0Sopenharmony_ci if (c % 16 == 15) 356d5ac70f0Sopenharmony_ci putchar('\n'); 357d5ac70f0Sopenharmony_ci } 358d5ac70f0Sopenharmony_ci if (c % 16 != 15) 359d5ac70f0Sopenharmony_ci putchar('\n'); 360d5ac70f0Sopenharmony_ci } 361d5ac70f0Sopenharmony_ci 362d5ac70f0Sopenharmony_ci set_event_header(&ev); 363d5ac70f0Sopenharmony_ci snd_seq_ev_set_sysex(&ev, len, msg); 364d5ac70f0Sopenharmony_ci write_ev(&ev); 365d5ac70f0Sopenharmony_ci} 366d5ac70f0Sopenharmony_ci 367d5ac70f0Sopenharmony_cistatic snd_seq_event_t *wait_for_event(void) 368d5ac70f0Sopenharmony_ci{ 369d5ac70f0Sopenharmony_ci int left; 370d5ac70f0Sopenharmony_ci snd_seq_event_t *input_event; 371d5ac70f0Sopenharmony_ci 372d5ac70f0Sopenharmony_ci if (use_blocking_mode) { 373d5ac70f0Sopenharmony_ci /* read the event - blocked until any event is read */ 374d5ac70f0Sopenharmony_ci left = snd_seq_event_input(seq_handle, &input_event); 375d5ac70f0Sopenharmony_ci } else { 376d5ac70f0Sopenharmony_ci /* read the event - using select syscall */ 377d5ac70f0Sopenharmony_ci while ((left = snd_seq_event_input(seq_handle, &input_event)) >= 0 && 378d5ac70f0Sopenharmony_ci input_event == NULL) { 379d5ac70f0Sopenharmony_ci int npfds = snd_seq_poll_descriptors_count(seq_handle, POLLIN); 380d5ac70f0Sopenharmony_ci struct pollfd *pfds = alloca(sizeof(*pfds) * npfds); 381d5ac70f0Sopenharmony_ci snd_seq_poll_descriptors(seq_handle, pfds, npfds, POLLIN); 382d5ac70f0Sopenharmony_ci if ((left = poll(pfds, npfds, -1)) < 0) { 383d5ac70f0Sopenharmony_ci printf("poll error = %i (%s)\n", errno, snd_strerror(errno)); 384d5ac70f0Sopenharmony_ci exit(1); 385d5ac70f0Sopenharmony_ci } 386d5ac70f0Sopenharmony_ci } 387d5ac70f0Sopenharmony_ci } 388d5ac70f0Sopenharmony_ci 389d5ac70f0Sopenharmony_ci if (left < 0) { 390d5ac70f0Sopenharmony_ci printf("alsa_sync error!:%s\n", snd_strerror(left)); 391d5ac70f0Sopenharmony_ci return NULL; 392d5ac70f0Sopenharmony_ci } 393d5ac70f0Sopenharmony_ci 394d5ac70f0Sopenharmony_ci return input_event; 395d5ac70f0Sopenharmony_ci} 396d5ac70f0Sopenharmony_ci 397d5ac70f0Sopenharmony_ci/* synchronize to the end of the event */ 398d5ac70f0Sopenharmony_cistatic void alsa_sync(void) 399d5ac70f0Sopenharmony_ci{ 400d5ac70f0Sopenharmony_ci /* send the echo event to the self client. */ 401d5ac70f0Sopenharmony_ci if (verbose >= VERB_MUCH) 402d5ac70f0Sopenharmony_ci printf("alsa_sync syncing...\n"); 403d5ac70f0Sopenharmony_ci /* dump the buffer */ 404d5ac70f0Sopenharmony_ci snd_seq_drain_output(seq_handle); 405d5ac70f0Sopenharmony_ci snd_seq_sync_output_queue(seq_handle); 406d5ac70f0Sopenharmony_ci if (verbose >= VERB_MUCH) 407d5ac70f0Sopenharmony_ci printf("alsa_sync synced\n"); 408d5ac70f0Sopenharmony_ci sleep(1); /* give a time for note releasing.. */ 409d5ac70f0Sopenharmony_ci} 410d5ac70f0Sopenharmony_ci 411d5ac70f0Sopenharmony_ci 412d5ac70f0Sopenharmony_ci/* wait for the start of the queue */ 413d5ac70f0Sopenharmony_cistatic void wait_start(void) 414d5ac70f0Sopenharmony_ci{ 415d5ac70f0Sopenharmony_ci snd_seq_event_t *input_event; 416d5ac70f0Sopenharmony_ci 417d5ac70f0Sopenharmony_ci /* wait for the start event from the system timer */ 418d5ac70f0Sopenharmony_ci for (;;) { 419d5ac70f0Sopenharmony_ci input_event = wait_for_event(); 420d5ac70f0Sopenharmony_ci if (input_event) { 421d5ac70f0Sopenharmony_ci if (verbose >= VERB_MUCH) 422d5ac70f0Sopenharmony_ci printf("wait_start got event. type=%d, flags=%d\n", 423d5ac70f0Sopenharmony_ci input_event->type, input_event->flags); 424d5ac70f0Sopenharmony_ci if (input_event->type == SND_SEQ_EVENT_START && 425d5ac70f0Sopenharmony_ci input_event->data.queue.queue == dest_queue) { 426d5ac70f0Sopenharmony_ci snd_seq_free_event(input_event); 427d5ac70f0Sopenharmony_ci break; 428d5ac70f0Sopenharmony_ci } 429d5ac70f0Sopenharmony_ci snd_seq_free_event(input_event); 430d5ac70f0Sopenharmony_ci } 431d5ac70f0Sopenharmony_ci } 432d5ac70f0Sopenharmony_ci if (verbose >= VERB_MUCH) 433d5ac70f0Sopenharmony_ci printf("start received\n"); 434d5ac70f0Sopenharmony_ci} 435d5ac70f0Sopenharmony_ci 436d5ac70f0Sopenharmony_ci 437d5ac70f0Sopenharmony_ci/* print the usage */ 438d5ac70f0Sopenharmony_cistatic void usage(void) 439d5ac70f0Sopenharmony_ci{ 440d5ac70f0Sopenharmony_ci fprintf(stderr, "usage: playmidi1 [options] [file]\n"); 441d5ac70f0Sopenharmony_ci fprintf(stderr, " options:\n"); 442d5ac70f0Sopenharmony_ci fprintf(stderr, " -v: verbose mode\n"); 443d5ac70f0Sopenharmony_ci fprintf(stderr, " -a client:port : set destination address (default=%d:%d)\n", 444d5ac70f0Sopenharmony_ci DEST_CLIENT_NUMBER, DEST_PORT_NUMBER); 445d5ac70f0Sopenharmony_ci fprintf(stderr, " -q queue: use the specified queue\n"); 446d5ac70f0Sopenharmony_ci fprintf(stderr, " -s queue: slave mode (allow external clock synchronization)\n"); 447d5ac70f0Sopenharmony_ci fprintf(stderr, " -r : play on real-time mode\n"); 448d5ac70f0Sopenharmony_ci fprintf(stderr, " -b : play on non-blocking mode\n"); 449d5ac70f0Sopenharmony_ci} 450d5ac70f0Sopenharmony_ci 451d5ac70f0Sopenharmony_ciint main(int argc, char *argv[]) 452d5ac70f0Sopenharmony_ci{ 453d5ac70f0Sopenharmony_ci int tmp; 454d5ac70f0Sopenharmony_ci int c; 455d5ac70f0Sopenharmony_ci snd_seq_addr_t dest_addr; 456d5ac70f0Sopenharmony_ci const char *addr = "65:0"; 457d5ac70f0Sopenharmony_ci 458d5ac70f0Sopenharmony_ci while ((c = getopt(argc, argv, "s:a:p:q:vrb")) != -1) { 459d5ac70f0Sopenharmony_ci switch (c) { 460d5ac70f0Sopenharmony_ci case 'v': 461d5ac70f0Sopenharmony_ci verbose++; 462d5ac70f0Sopenharmony_ci break; 463d5ac70f0Sopenharmony_ci case 'a': 464d5ac70f0Sopenharmony_ci case 'p': 465d5ac70f0Sopenharmony_ci addr = optarg; 466d5ac70f0Sopenharmony_ci break; 467d5ac70f0Sopenharmony_ci case 'q': 468d5ac70f0Sopenharmony_ci dest_queue = atoi(optarg); 469d5ac70f0Sopenharmony_ci if (dest_queue < 0) { 470d5ac70f0Sopenharmony_ci fprintf(stderr, "invalid queue number %d\n", dest_queue); 471d5ac70f0Sopenharmony_ci exit(1); 472d5ac70f0Sopenharmony_ci } 473d5ac70f0Sopenharmony_ci break; 474d5ac70f0Sopenharmony_ci case 's': 475d5ac70f0Sopenharmony_ci slave = 1; 476d5ac70f0Sopenharmony_ci dest_queue = atoi(optarg); 477d5ac70f0Sopenharmony_ci if (dest_queue < 0) { 478d5ac70f0Sopenharmony_ci fprintf(stderr, "invalid queue number %d\n", dest_queue); 479d5ac70f0Sopenharmony_ci exit(1); 480d5ac70f0Sopenharmony_ci } 481d5ac70f0Sopenharmony_ci break; 482d5ac70f0Sopenharmony_ci case 'r': 483d5ac70f0Sopenharmony_ci use_realtime = 1; 484d5ac70f0Sopenharmony_ci break; 485d5ac70f0Sopenharmony_ci case 'b': 486d5ac70f0Sopenharmony_ci use_blocking_mode = 0; 487d5ac70f0Sopenharmony_ci break; 488d5ac70f0Sopenharmony_ci default: 489d5ac70f0Sopenharmony_ci usage(); 490d5ac70f0Sopenharmony_ci exit(1); 491d5ac70f0Sopenharmony_ci } 492d5ac70f0Sopenharmony_ci } 493d5ac70f0Sopenharmony_ci 494d5ac70f0Sopenharmony_ci if (verbose >= VERB_INFO) { 495d5ac70f0Sopenharmony_ci if (use_realtime) 496d5ac70f0Sopenharmony_ci printf("ALSA MIDI Player, feeding events to real-time queue\n"); 497d5ac70f0Sopenharmony_ci else 498d5ac70f0Sopenharmony_ci printf("ALSA MIDI Player, feeding events to song queue\n"); 499d5ac70f0Sopenharmony_ci } 500d5ac70f0Sopenharmony_ci 501d5ac70f0Sopenharmony_ci /* open the sequencer device */ 502d5ac70f0Sopenharmony_ci /* Here we open the device in read/write for slave mode. */ 503d5ac70f0Sopenharmony_ci tmp = snd_seq_open(&seq_handle, "hw", slave ? SND_SEQ_OPEN_DUPLEX : SND_SEQ_OPEN_OUTPUT, 0); 504d5ac70f0Sopenharmony_ci if (tmp < 0) { 505d5ac70f0Sopenharmony_ci perror("open /dev/snd/seq"); 506d5ac70f0Sopenharmony_ci exit(1); 507d5ac70f0Sopenharmony_ci } 508d5ac70f0Sopenharmony_ci 509d5ac70f0Sopenharmony_ci tmp = snd_seq_nonblock(seq_handle, !use_blocking_mode); 510d5ac70f0Sopenharmony_ci if (tmp < 0) { 511d5ac70f0Sopenharmony_ci perror("block_mode"); 512d5ac70f0Sopenharmony_ci exit(1); 513d5ac70f0Sopenharmony_ci } 514d5ac70f0Sopenharmony_ci 515d5ac70f0Sopenharmony_ci /* set the name */ 516d5ac70f0Sopenharmony_ci /* set the event filter to receive only the echo event */ 517d5ac70f0Sopenharmony_ci /* if running in slave mode, also listen for a START event */ 518d5ac70f0Sopenharmony_ci if (slave) 519d5ac70f0Sopenharmony_ci snd_seq_set_client_event_filter(seq_handle, SND_SEQ_EVENT_START); 520d5ac70f0Sopenharmony_ci snd_seq_set_client_name(seq_handle, "MIDI file player"); 521d5ac70f0Sopenharmony_ci 522d5ac70f0Sopenharmony_ci /* create the port */ 523d5ac70f0Sopenharmony_ci my_port = snd_seq_create_simple_port(seq_handle, "Port 0", 524d5ac70f0Sopenharmony_ci SND_SEQ_PORT_CAP_WRITE | 525d5ac70f0Sopenharmony_ci SND_SEQ_PORT_CAP_READ, 526d5ac70f0Sopenharmony_ci SND_SEQ_PORT_TYPE_MIDI_GENERIC); 527d5ac70f0Sopenharmony_ci if (my_port < 0) { 528d5ac70f0Sopenharmony_ci perror("create port"); 529d5ac70f0Sopenharmony_ci exit(1); 530d5ac70f0Sopenharmony_ci } 531d5ac70f0Sopenharmony_ci 532d5ac70f0Sopenharmony_ci if (snd_seq_parse_address(seq_handle, &dest_addr, addr) < 0) { 533d5ac70f0Sopenharmony_ci perror("invalid destination address"); 534d5ac70f0Sopenharmony_ci exit(1); 535d5ac70f0Sopenharmony_ci } 536d5ac70f0Sopenharmony_ci dest_client = dest_addr.client; 537d5ac70f0Sopenharmony_ci dest_port = dest_addr.port; 538d5ac70f0Sopenharmony_ci 539d5ac70f0Sopenharmony_ci /* set the queue */ 540d5ac70f0Sopenharmony_ci if (dest_queue >= 0) { 541d5ac70f0Sopenharmony_ci shared_queue = 1; 542d5ac70f0Sopenharmony_ci if (snd_seq_set_queue_usage(seq_handle, dest_queue, 1) < 0) { 543d5ac70f0Sopenharmony_ci perror("use queue"); 544d5ac70f0Sopenharmony_ci exit(1); 545d5ac70f0Sopenharmony_ci } 546d5ac70f0Sopenharmony_ci } else { 547d5ac70f0Sopenharmony_ci shared_queue = 0; 548d5ac70f0Sopenharmony_ci dest_queue = snd_seq_alloc_queue(seq_handle); 549d5ac70f0Sopenharmony_ci if (dest_queue < 0) { 550d5ac70f0Sopenharmony_ci perror("alloc queue"); 551d5ac70f0Sopenharmony_ci exit(1); 552d5ac70f0Sopenharmony_ci } 553d5ac70f0Sopenharmony_ci } 554d5ac70f0Sopenharmony_ci 555d5ac70f0Sopenharmony_ci /* set the subscriber */ 556d5ac70f0Sopenharmony_ci tmp = snd_seq_connect_to(seq_handle, my_port, dest_client, dest_port); 557d5ac70f0Sopenharmony_ci if (tmp < 0) { 558d5ac70f0Sopenharmony_ci perror("subscribe"); 559d5ac70f0Sopenharmony_ci exit(1); 560d5ac70f0Sopenharmony_ci } 561d5ac70f0Sopenharmony_ci 562d5ac70f0Sopenharmony_ci /* subscribe for the timer START event */ 563d5ac70f0Sopenharmony_ci if (slave) { 564d5ac70f0Sopenharmony_ci tmp = snd_seq_connect_from(seq_handle, my_port, 565d5ac70f0Sopenharmony_ci SND_SEQ_CLIENT_SYSTEM, 566d5ac70f0Sopenharmony_ci dest_queue + 16 /*snd_seq_queue_sync_port(dest_queue)*/); 567d5ac70f0Sopenharmony_ci if (tmp < 0) { 568d5ac70f0Sopenharmony_ci perror("subscribe"); 569d5ac70f0Sopenharmony_ci exit(1); 570d5ac70f0Sopenharmony_ci } 571d5ac70f0Sopenharmony_ci } 572d5ac70f0Sopenharmony_ci 573d5ac70f0Sopenharmony_ci /* change the pool size */ 574d5ac70f0Sopenharmony_ci if (snd_seq_set_client_pool_output(seq_handle, WRITE_POOL_SIZE) < 0 || 575d5ac70f0Sopenharmony_ci snd_seq_set_client_pool_input(seq_handle, READ_POOL_SIZE) < 0 || 576d5ac70f0Sopenharmony_ci snd_seq_set_client_pool_output_room(seq_handle, WRITE_POOL_SPACE) < 0) { 577d5ac70f0Sopenharmony_ci perror("pool"); 578d5ac70f0Sopenharmony_ci exit(1); 579d5ac70f0Sopenharmony_ci } 580d5ac70f0Sopenharmony_ci 581d5ac70f0Sopenharmony_ci if (optind < argc) { 582d5ac70f0Sopenharmony_ci F = fopen(argv[optind], "r"); 583d5ac70f0Sopenharmony_ci if (F == NULL) { 584d5ac70f0Sopenharmony_ci fprintf(stderr, "playmidi1: can't open file %s\n", argv[optind]); 585d5ac70f0Sopenharmony_ci exit(1); 586d5ac70f0Sopenharmony_ci } 587d5ac70f0Sopenharmony_ci } else 588d5ac70f0Sopenharmony_ci F = stdin; 589d5ac70f0Sopenharmony_ci 590d5ac70f0Sopenharmony_ci Mf_header = do_header; 591d5ac70f0Sopenharmony_ci Mf_tempo = do_tempo; 592d5ac70f0Sopenharmony_ci Mf_getc = mygetc; 593d5ac70f0Sopenharmony_ci Mf_text = mytext; 594d5ac70f0Sopenharmony_ci 595d5ac70f0Sopenharmony_ci Mf_noteon = do_noteon; 596d5ac70f0Sopenharmony_ci Mf_noteoff = do_noteoff; 597d5ac70f0Sopenharmony_ci Mf_program = do_program; 598d5ac70f0Sopenharmony_ci Mf_parameter = do_parameter; 599d5ac70f0Sopenharmony_ci Mf_pitchbend = do_pitchbend; 600d5ac70f0Sopenharmony_ci Mf_pressure = do_pressure; 601d5ac70f0Sopenharmony_ci Mf_chanpressure = do_chanpressure; 602d5ac70f0Sopenharmony_ci Mf_sysex = do_sysex; 603d5ac70f0Sopenharmony_ci 604d5ac70f0Sopenharmony_ci /* go.. go.. go.. */ 605d5ac70f0Sopenharmony_ci mfread(); 606d5ac70f0Sopenharmony_ci 607d5ac70f0Sopenharmony_ci alsa_sync(); 608d5ac70f0Sopenharmony_ci if (! shared_queue) 609d5ac70f0Sopenharmony_ci alsa_stop_timer(); 610d5ac70f0Sopenharmony_ci 611d5ac70f0Sopenharmony_ci snd_seq_close(seq_handle); 612d5ac70f0Sopenharmony_ci 613d5ac70f0Sopenharmony_ci if (verbose >= VERB_INFO) { 614d5ac70f0Sopenharmony_ci printf("Stopping at %f s, tick %f\n", 615d5ac70f0Sopenharmony_ci tick2time_dbl(Mf_currtime + 1), (double) (Mf_currtime + 1)); 616d5ac70f0Sopenharmony_ci } 617d5ac70f0Sopenharmony_ci 618d5ac70f0Sopenharmony_ci exit(0); 619d5ac70f0Sopenharmony_ci} 620