/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $URL$ * $Id$ * */ #include #include "../device.h" #ifdef HAVE_ALSA #include #define SCI_ALSA_MIDI_VERSION "0.1" static snd_midi_event_t *parser = NULL; static snd_seq_t *seq = NULL; static int queue = -1; static int delta = 0; static int port_out = -1; static int port_nr = 128; static int subport_nr = 0; static const char *seq_name = "default"; static void _set_tempo(void) { int resolution = 60; int tempo = 1; snd_seq_queue_tempo_t *queue_tempo; snd_seq_queue_tempo_malloc(&queue_tempo); memset(queue_tempo, 0, snd_seq_queue_tempo_sizeof()); snd_seq_queue_tempo_set_ppq(queue_tempo, resolution); snd_seq_queue_tempo_set_tempo(queue_tempo, 1000000 / tempo); snd_seq_set_queue_tempo(seq, queue, queue_tempo); snd_seq_queue_tempo_free(queue_tempo); #if 0 int tempo = 1000000 / 60; snd_seq_queue_tempo_t *queue_tempo; snd_seq_queue_tempo_malloc(&queue_tempo); snd_seq_queue_tempo_set_tempo(queue_tempo, tempo); snd_seq_queue_tempo_set_ppq(queue_tempo, 1); snd_seq_set_queue_tempo(seq, queue, queue_tempo); snd_seq_queue_tempo_free(queue_tempo); #endif } static int am_subscribe_to_ports(void) { if ((port_out = snd_seq_connect_to(seq, port_out, port_nr, subport_nr)) < 0) { fprintf(stderr, "[SFX] Could not connect to ALSA sequencer port: %s\n", snd_strerror(port_out)); return SFX_ERROR; } return SFX_OK; } static int aminit(midi_writer_t *self) { int err; snd_midi_event_new(4096, &parser); snd_midi_event_init(parser); sciprintf("[SFX] Initialising ALSA MIDI backend, v%s\n", SCI_ALSA_MIDI_VERSION); if (snd_seq_open(&seq, seq_name, SND_SEQ_OPEN_OUTPUT, SND_SEQ_NONBLOCK)) { fprintf(stderr, "[SFX] Failed to open ALSA MIDI sequencer '%s' for output\n", seq_name); return SFX_ERROR; } if ((port_out = snd_seq_create_simple_port(seq, "FreeSCI", SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC)) < 0) { fprintf(stderr, "[SFX] Could not create ALSA sequencer port\n"); return SFX_ERROR; } if (am_subscribe_to_ports()) return SFX_ERROR; queue = snd_seq_alloc_queue(seq); _set_tempo(); snd_seq_start_queue(seq, queue, NULL); if ((err = snd_seq_drain_output(seq))) { fflush(NULL); fprintf(stderr, "[SFX] Error while draining: %s\n", snd_strerror(err)); return SFX_ERROR; } return SFX_OK; } static int amsetopt(midi_writer_t *self, char *name, char *value) { return SFX_ERROR; } static int amwrite(midi_writer_t *self, unsigned char *buf, int len) { snd_seq_event_t evt; #if 0 { int i; fprintf(stderr, "[MID] "); for (i = 0; i < len; i++) fprintf(stderr, " %02x", buf[i]); fprintf(stderr, "\n"); } #endif snd_seq_ev_clear(&evt); snd_seq_ev_set_source(&evt, port_out); snd_seq_ev_set_subs(&evt); /* Broadcast to all subscribers */ snd_midi_event_encode(parser, buf, len, &evt); snd_seq_ev_schedule_tick(&evt, queue, 0, delta); snd_seq_event_output_direct(seq, &evt); #if 0 { snd_seq_queue_status_t *status; snd_seq_queue_status_malloc(&status); snd_seq_get_queue_status(seq, queue, status); //snd_seq_tick_time_t snd_seq_queue_status_get_tick_time(const snd_seq_queue_status_t *info); fprintf(stderr, "Queue at %d/%d\n", delta, snd_seq_queue_status_get_tick_time(status)); snd_seq_queue_status_free(status); } #endif return SFX_OK; } static void amdelay(midi_writer_t *self, int ticks) { delta += ticks; } static void amreset_timer(midi_writer_t *self) { snd_seq_drain_output(seq); snd_seq_stop_queue(seq, queue, NULL); { snd_seq_event_t evt; snd_seq_ev_clear(&evt); snd_seq_ev_set_source(&evt, port_out); snd_seq_ev_set_subs(&evt); /* Broadcast to all subscribers */ snd_seq_ev_set_queue_pos_tick(&evt, queue, 0); snd_seq_event_output_direct(seq, &evt); } delta = 0; snd_seq_start_queue(seq, queue, NULL); } static void amclose(midi_writer_t *self) { snd_midi_event_free(parser); parser = NULL; } midi_writer_t sfx_device_midi_alsa = { "alsa", aminit, amsetopt, amwrite, amdelay, NULL, amreset_timer, amclose, }; #endif