/* Copyright (C) Dima Simakov 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., 675 Mass Ave, Cambridge, MA 02139, USA. esd_a.c -- functions to play sound on Enlightened Sound Daemon by Carsten Haitzler (aka The Rasterman). */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include "timidity.h" #include "common.h" #include "output.h" #include "controls.h" #include "timer.h" #include "instrum.h" #include "playmidi.h" #include "miditrace.h" static int open_output(void); /* 0=success, 1=warning, -1=fatal error */ static void close_output(void); static void output_data(int32 *buf, int32 count); static int flush_output(void); static void purge_output(void); static int32 current_samples(void); static int play_loop(void); extern int default_play_event(void *); static int esd; /* esd socket */ static int32 play_counter, reset_samples; static double play_start_time; static char esd_stream_name[] = "Timidity"; #define dpm esd_play_mode PlayMode dpm = { DEFAULT_RATE, PE_16BIT|PE_SIGNED, PF_NEED_INSTRUMENTS|PF_CAN_TRACE, -1, {0}, "EsounD network audio", 'e', "localhost:5001", default_play_event, open_output, close_output, output_data, flush_output, purge_output, current_samples, play_loop }; static int open_output(void) { gint rate, bits, channels, mode, func, format; if(dpm.encoding & PE_ALAW) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: A-Law is not supported by EsounD", dpm.name); return -1; } if(dpm.encoding & PE_ULAW) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: U-Law is not supported by EsounD", dpm.name); return -1; } channels = (dpm.encoding & PE_MONO) ? ESD_MONO : ESD_STEREO; rate = dpm.rate; bits = (dpm.encoding & PE_16BIT) ? ESD_BITS16 : ESD_BITS8; mode = ESD_STREAM; func = ESD_PLAY; format = bits | channels | mode | func; esd = 0; esd = esd_play_stream( format, rate, dpm.name, esd_stream_name ); if ( esd == -1) { ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Cannot open connection to EsounD daemon"); ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Tyring to start daemon ;)"); system("esd &"); sleep(3); esd = esd_play_stream( format, rate, dpm.name, esd_stream_name ); if ( esd == -1) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Cannot connect to daemon... sorry ;("); return -1; } } return(0); } static void add_sample_counter(int32 count) { current_samples(); /* update offset_samples */ play_counter += count; } static void output_data(int32 *buf, int32 count) { int32 add_count = count; if (!(dpm.encoding & PE_MONO)) count*=2; if (dpm.encoding & PE_16BIT) { s32tos16(buf, count); count *= 2; } else s32tos8(buf, count); add_sample_counter(add_count); if (write( esd, buf, count ) < 0 ) { ctl->cmsg(CMSG_ERROR,VERB_NORMAL,"EsounD write FAILED"); ctl->close(); exit(1); } } static void close_output(void) { close( esd ); play_counter = reset_samples = 0; dpm.fd=-1; } static int flush_output(void) { int rc; while(trace_loop()) { rc = check_apply_control(); if(RC_IS_SKIP_FILE(rc)) { purge_output(); return rc; } } do { rc = check_apply_control(); if(RC_IS_SKIP_FILE(rc)) { purge_output(); return rc; } current_samples(); #ifdef HAVE_USLEEP usleep(100000); #endif } while(play_counter > 0); play_counter = reset_samples = 0; return RC_NONE; } static void purge_output(void) { play_counter = reset_samples = 0; } static int play_loop(void) { return 0; } static int32 current_samples(void) { double realtime, es; realtime = get_current_calender_time(); if(play_counter == 0) { play_start_time = realtime; return reset_samples; } es = dpm.rate * (realtime - play_start_time); if(es >= play_counter) { reset_samples += play_counter; play_counter = 0; play_start_time = realtime; return reset_samples; } if(es < 0) return 0; return (int32)es + reset_samples; }