1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 
20     esd_a.c by Avatar <avatar@deva.net>
21     based on linux_a.c
22 
23     Functions to play sound through EsounD
24 */
25 
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #define _GNU_SOURCE
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <dlfcn.h>
35 
36 #ifndef NO_STRING_H
37 #include <string.h>
38 #else
39 #include <strings.h>
40 #endif
41 
42 #include <esd.h>
43 
44 #include "timidity.h"
45 #include "common.h"
46 #include "output.h"
47 #include "controls.h"
48 #include "timer.h"
49 #include "instrum.h"
50 #include "playmidi.h"
51 #include "miditrace.h"
52 
53 static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
54 static void close_output(void);
55 static int output_data(char *buf, int32 nbytes);
56 static int acntl(int request, void *arg);
57 static int detect(void);
58 
59 
60 /* export the playback mode */
61 
62 #define dpm esd_play_mode
63 
64 PlayMode dpm = {
65     DEFAULT_RATE,
66     PE_16BIT|PE_SIGNED,
67     PF_PCM_STREAM/*|PF_CAN_TRACE*/,
68     -1,
69     {0}, /* default: get all the buffer fragments you can */
70     "Enlightened sound daemon", 'e',
71     "esd",
72     open_output,
73     close_output,
74     output_data,
75     acntl,
76     detect
77 };
78 
79 
try_open(void)80 static int try_open(void)
81 {
82     int include_enc, exclude_enc;
83     esd_format_t esdformat;
84 
85     include_enc = 0;
86     exclude_enc = PE_ULAW|PE_ALAW|PE_BYTESWAP; /* They can't mean these */
87     if(dpm.encoding & PE_16BIT)
88 	include_enc |= PE_SIGNED;
89     else
90 	exclude_enc |= PE_SIGNED;
91     dpm.encoding = validate_encoding(dpm.encoding, include_enc, exclude_enc);
92 
93     /* Open the audio device */
94     esdformat = (dpm.encoding & PE_16BIT) ? ESD_BITS16 : ESD_BITS8;
95     esdformat |= (dpm.encoding & PE_MONO) ? ESD_MONO : ESD_STEREO;
96     return esd_play_stream(esdformat,dpm.rate,NULL,"timidity");
97 }
98 
99 
detect(void)100 static int detect(void)
101 {
102     int fd;
103 
104     setenv("ESD_NO_SPAWN", "1", 0);
105     fd = try_open();
106     if (fd < 0)
107 	return 0;
108     close(fd);
109     return 1; /* found */
110 }
111 
112 /*************************************************************************/
113 /* We currently only honor the PE_MONO bit, and the sample rate. */
114 
open_output(void)115 static int open_output(void)
116 {
117     int fd;
118 
119     fd = try_open();
120 
121     if(fd < 0)
122     {
123 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
124 		  dpm.name, strerror(errno));
125 	return -1;
126     }
127 
128 
129     dpm.fd = fd;
130 
131     return 0;
132 }
133 
output_data(char * buf,int32 nbytes)134 static int output_data(char *buf, int32 nbytes)
135 {
136     int n;
137 
138     //    write(1, buf, nbytes);return 0;
139 
140     while(nbytes > 0)
141     {
142 	if((n = write(dpm.fd, buf, nbytes)) == -1)
143 	{
144 	    ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
145 		      "%s: %s", dpm.name, strerror(errno));
146 	    if(errno == EWOULDBLOCK)
147 	    {
148 		/* It is possible to come here because of bug of the
149 		 * sound driver.
150 		 */
151 		continue;
152 	    }
153 	    return -1;
154 	}
155 	buf += n;
156 	nbytes -= n;
157     }
158 
159     return 0;
160 }
161 
close_output(void)162 static void close_output(void)
163 {
164     if(dpm.fd == -1)
165 	return;
166     close(dpm.fd);
167     dpm.fd = -1;
168 }
169 
acntl(int request,void * arg)170 static int acntl(int request, void *arg)
171 {
172     switch(request)
173     {
174       case PM_REQ_DISCARD:
175         esd_audio_flush();
176 	return 0;
177 
178       case PM_REQ_RATE: {
179 	  /* not implemented yet */
180           break;
181 	}
182 
183       case PM_REQ_PLAY_START: /* Called just before playing */
184       case PM_REQ_PLAY_END: /* Called just after playing */
185         return 0;
186     }
187     return -1;
188 }
189